1 #include "bcdisplayinfo.h"
4 #include "mainprogress.h"
7 #include "timestretch.h"
8 #include "timestretchengine.h"
13 #define _(String) gettext(String)
14 #define gettext_noop(String) String
15 #define N_(String) gettext_noop (String)
18 #define WINDOW_SIZE 8192
21 PluginClient* new_plugin(PluginServer *server)
23 return new TimeStretch(server);
29 TimeStretchFraction::TimeStretchFraction(TimeStretch *plugin, int x, int y)
30 : BC_TextBox(x, y, 100, 1, (float)plugin->scale)
32 this->plugin = plugin;
35 int TimeStretchFraction::handle_event()
37 plugin->scale = atof(get_text());
45 TimeStretchFreq::TimeStretchFreq(TimeStretch *plugin,
46 TimeStretchWindow *gui,
49 : BC_Radial(x, y, plugin->use_fft, _("Use fast fourier transform"))
51 this->plugin = plugin;
55 int TimeStretchFreq::handle_event()
67 TimeStretchTime::TimeStretchTime(TimeStretch *plugin,
68 TimeStretchWindow *gui,
71 : BC_Radial(x, y, !plugin->use_fft, _("Use overlapping windows"))
73 this->plugin = plugin;
77 int TimeStretchTime::handle_event()
95 TimeStretchWindow::TimeStretchWindow(TimeStretch *plugin, int x, int y)
96 : BC_Window(PROGRAM_NAME ": Time stretch",
107 this->plugin = plugin;
111 TimeStretchWindow::~TimeStretchWindow()
115 void TimeStretchWindow::create_objects()
119 add_subwindow(new BC_Title(x, y, _("Fraction of original length:")));
121 add_subwindow(new TimeStretchFraction(plugin, x, y));
124 add_subwindow(freq = new TimeStretchFreq(plugin, this, x, y));
126 add_subwindow(time = new TimeStretchTime(plugin, this, x, y));
128 add_subwindow(new BC_OKButton(this));
129 add_subwindow(new BC_CancelButton(this));
146 PitchEngine::PitchEngine(TimeStretch *plugin)
149 this->plugin = plugin;
153 int PitchEngine::signal_process()
157 1 + (int)(20.0 / ((double)plugin->PluginAClient::project_sample_rate / window_size * 2) + 0.5);
159 if(plugin->scale < 1)
161 for(int i = min_freq; i < window_size / 2; i++)
163 double destination = i * plugin->scale;
164 int dest_i = (int)(destination + 0.5);
167 if(dest_i <= window_size / 2)
169 freq_real[dest_i] = freq_real[i];
170 freq_imag[dest_i] = freq_imag[i];
178 if(plugin->scale > 1)
180 //printf("PitchEngine::signal_process 1\n");
181 for(int i = window_size / 2 - 1; i >= min_freq; i--)
183 double destination = i * plugin->scale;
184 int dest_i = (int)(destination + 0.5);
187 if(dest_i <= window_size / 2)
189 freq_real[dest_i] = freq_real[i];
190 freq_imag[dest_i] = freq_imag[i];
196 //printf("PitchEngine::signal_process 1\n");
199 symmetry(window_size, freq_real, freq_imag);
200 //printf("PitchEngine::signal_process 2\n");
217 TimeStretch::TimeStretch(PluginServer *server)
218 : PluginAClient(server)
230 TimeStretch::~TimeStretch()
234 if(temp) delete [] temp;
235 if(input) delete [] input;
236 if(pitch) delete pitch;
237 if(resample) delete resample;
238 if(stretch) delete stretch;
243 char* TimeStretch::plugin_title()
245 return _("Time stretch");
248 int TimeStretch::get_parameters()
251 TimeStretchWindow window(this, info.get_abs_cursor_x(), info.get_abs_cursor_y());
252 window.create_objects();
253 int result = window.run_window();
258 VFrame* TimeStretch::new_picon()
260 return new VFrame(picon_png);
264 int TimeStretch::start_loop()
266 if(PluginClient::interactive)
268 char string[BCTEXTLEN];
269 sprintf(string, "%s...", plugin_title());
270 progress = start_progress(string,
271 (int64_t)((double)(PluginClient::end - PluginClient::start) * scale));
274 current_position = PluginClient::start;
282 pitch = new PitchEngine(this);
283 pitch->initialize(WINDOW_SIZE);
284 resample = new Resample(0, 1);
287 // The windowing case
289 // Must be short enough to mask beating but long enough to mask humming.
290 stretch = new TimeStretchEngine(scale, PluginAClient::project_sample_rate);
299 int TimeStretch::stop_loop()
301 if(PluginClient::interactive)
303 progress->stop_progress();
309 int TimeStretch::process_loop(double *buffer, int64_t &write_length)
311 //printf("TimeStretch::process_loop 1\n");
313 // Length to read based on desired output size
314 int64_t size = (int64_t)((double)PluginAClient::in_buffer_size / scale);
315 int64_t predicted_total = (int64_t)((double)(PluginClient::end - PluginClient::start) * scale + 0.5);
316 int samples_rendered = 0;
318 if(input_allocated < size)
320 if(input) delete [] input;
321 input = new double[size];
322 input_allocated = size;
325 read_samples(input, 0, current_position, size);
326 current_position += size;
333 resample->resample_chunk(input,
336 (int)(1000000.0 * scale),
340 if(resample->get_output_size(0))
342 int64_t output_size = resample->get_output_size(0);
343 if(temp && temp_allocated < output_size)
351 temp = new double[output_size];
352 temp_allocated = output_size;
354 resample->read_output(temp, 0, output_size);
357 samples_rendered = pitch->process_fifo(output_size,
365 // The windowing case
367 //printf("TimeStretch::process_loop 10\n");
368 samples_rendered = stretch->process(input, size);
369 //printf("TimeStretch::process_loop 20 %d\n", samples_rendered);
372 samples_rendered = MIN(samples_rendered, PluginAClient::in_buffer_size);
373 stretch->read_output(buffer, samples_rendered);
375 //printf("TimeStretch::process_loop 30\n");
381 total_written += samples_rendered;
384 // Trim output to predicted length of stretched selection.
385 if(total_written > predicted_total)
387 samples_rendered -= total_written - predicted_total;
392 write_length = samples_rendered;
393 if(PluginClient::interactive) result = progress->update(total_written);
394 //printf("TimeStretch::process_loop 100\n");
401 int TimeStretch::load_defaults()
403 char directory[BCTEXTLEN];
405 // set the default directory
406 sprintf(directory, "%stimestretch.rc", BCASTDIR);
408 defaults = new Defaults(directory);
411 scale = defaults->get("SCALE", (double)1);
412 use_fft = defaults->get("USE_FFT", 0);
416 int TimeStretch::save_defaults()
418 defaults->update("SCALE", scale);
419 defaults->update("USE_FFT", use_fft);