1 #include "bcdisplayinfo.h"
4 #include "mainprogress.h"
7 #include "timestretch.h"
8 #include "timestretchengine.h"
11 #define WINDOW_SIZE 8192
14 PluginClient* new_plugin(PluginServer *server)
16 return new TimeStretch(server);
22 TimeStretchFraction::TimeStretchFraction(TimeStretch *plugin, int x, int y)
23 : BC_TextBox(x, y, 100, 1, (float)plugin->scale)
25 this->plugin = plugin;
28 int TimeStretchFraction::handle_event()
30 plugin->scale = atof(get_text());
38 TimeStretchFreq::TimeStretchFreq(TimeStretch *plugin,
39 TimeStretchWindow *gui,
42 : BC_Radial(x, y, plugin->use_fft, "Use fast fourier transform")
44 this->plugin = plugin;
48 int TimeStretchFreq::handle_event()
60 TimeStretchTime::TimeStretchTime(TimeStretch *plugin,
61 TimeStretchWindow *gui,
64 : BC_Radial(x, y, !plugin->use_fft, "Use overlapping windows")
66 this->plugin = plugin;
70 int TimeStretchTime::handle_event()
88 TimeStretchWindow::TimeStretchWindow(TimeStretch *plugin, int x, int y)
89 : BC_Window(PROGRAM_NAME ": Time stretch",
100 this->plugin = plugin;
104 TimeStretchWindow::~TimeStretchWindow()
108 void TimeStretchWindow::create_objects()
112 add_subwindow(new BC_Title(x, y, "Fraction of original length:"));
114 add_subwindow(new TimeStretchFraction(plugin, x, y));
117 add_subwindow(freq = new TimeStretchFreq(plugin, this, x, y));
119 add_subwindow(time = new TimeStretchTime(plugin, this, x, y));
121 add_subwindow(new BC_OKButton(this));
122 add_subwindow(new BC_CancelButton(this));
139 PitchEngine::PitchEngine(TimeStretch *plugin)
142 this->plugin = plugin;
146 int PitchEngine::signal_process()
150 1 + (int)(20.0 / ((double)plugin->PluginAClient::project_sample_rate / window_size * 2) + 0.5);
152 if(plugin->scale < 1)
154 for(int i = min_freq; i < window_size / 2; i++)
156 double destination = i * plugin->scale;
157 int dest_i = (int)(destination + 0.5);
160 if(dest_i <= window_size / 2)
162 freq_real[dest_i] = freq_real[i];
163 freq_imag[dest_i] = freq_imag[i];
171 if(plugin->scale > 1)
173 //printf("PitchEngine::signal_process 1\n");
174 for(int i = window_size / 2 - 1; i >= min_freq; i--)
176 double destination = i * plugin->scale;
177 int dest_i = (int)(destination + 0.5);
180 if(dest_i <= window_size / 2)
182 freq_real[dest_i] = freq_real[i];
183 freq_imag[dest_i] = freq_imag[i];
189 //printf("PitchEngine::signal_process 1\n");
192 symmetry(window_size, freq_real, freq_imag);
193 //printf("PitchEngine::signal_process 2\n");
210 TimeStretch::TimeStretch(PluginServer *server)
211 : PluginAClient(server)
223 TimeStretch::~TimeStretch()
227 if(temp) delete [] temp;
228 if(input) delete [] input;
229 if(pitch) delete pitch;
230 if(resample) delete resample;
231 if(stretch) delete stretch;
236 char* TimeStretch::plugin_title()
238 return "Time stretch";
241 int TimeStretch::get_parameters()
244 TimeStretchWindow window(this, info.get_abs_cursor_x(), info.get_abs_cursor_y());
245 window.create_objects();
246 int result = window.run_window();
251 VFrame* TimeStretch::new_picon()
253 return new VFrame(picon_png);
257 int TimeStretch::start_loop()
259 if(PluginClient::interactive)
261 char string[BCTEXTLEN];
262 sprintf(string, "%s...", plugin_title());
263 progress = start_progress(string,
264 (int64_t)((double)(PluginClient::end - PluginClient::start) * scale));
267 current_position = PluginClient::start;
275 pitch = new PitchEngine(this);
276 pitch->initialize(WINDOW_SIZE);
277 resample = new Resample(0, 1);
280 // The windowing case
282 // Must be short enough to mask beating but long enough to mask humming.
283 stretch = new TimeStretchEngine(scale, PluginAClient::project_sample_rate);
292 int TimeStretch::stop_loop()
294 if(PluginClient::interactive)
296 progress->stop_progress();
302 int TimeStretch::process_loop(double *buffer, int64_t &write_length)
304 //printf("TimeStretch::process_loop 1\n");
306 // Length to read based on desired output size
307 int64_t size = (int64_t)((double)PluginAClient::in_buffer_size / scale);
308 int64_t predicted_total = (int64_t)((double)(PluginClient::end - PluginClient::start) * scale + 0.5);
309 int samples_rendered = 0;
311 if(input_allocated < size)
313 if(input) delete [] input;
314 input = new double[size];
315 input_allocated = size;
318 read_samples(input, 0, current_position, size);
319 current_position += size;
326 resample->resample_chunk(input,
329 (int)(1000000.0 * scale),
333 if(resample->get_output_size(0))
335 int64_t output_size = resample->get_output_size(0);
336 if(temp && temp_allocated < output_size)
344 temp = new double[output_size];
345 temp_allocated = output_size;
347 resample->read_output(temp, 0, output_size);
350 samples_rendered = pitch->process_fifo(output_size,
358 // The windowing case
360 //printf("TimeStretch::process_loop 10\n");
361 samples_rendered = stretch->process(input, size);
362 //printf("TimeStretch::process_loop 20 %d\n", samples_rendered);
365 samples_rendered = MIN(samples_rendered, PluginAClient::in_buffer_size);
366 stretch->read_output(buffer, samples_rendered);
368 //printf("TimeStretch::process_loop 30\n");
374 total_written += samples_rendered;
377 // Trim output to predicted length of stretched selection.
378 if(total_written > predicted_total)
380 samples_rendered -= total_written - predicted_total;
385 write_length = samples_rendered;
386 if(PluginClient::interactive) result = progress->update(total_written);
387 //printf("TimeStretch::process_loop 100\n");
394 int TimeStretch::load_defaults()
396 char directory[BCTEXTLEN];
398 // set the default directory
399 sprintf(directory, "%stimestretch.rc", BCASTDIR);
401 defaults = new Defaults(directory);
404 scale = defaults->get("SCALE", (double)1);
405 use_fft = defaults->get("USE_FFT", 0);
409 int TimeStretch::save_defaults()
411 defaults->update("SCALE", scale);
412 defaults->update("USE_FFT", use_fft);