r125: This commit was manufactured by cvs2svn to create tag 'r1_1_7-last'.
[cinelerra_cv/mob.git] / hvirtual / plugins / timestretch / timestretch.C
blobcb687975b891912c0ae29ae0ce4e7ba34fa8bd37
1 #include "bcdisplayinfo.h"
2 #include "clip.h"
3 #include "defaults.h"
4 #include "mainprogress.h"
5 #include "picon_png.h"
6 #include "resample.h"
7 #include "timestretch.h"
8 #include "timestretchengine.h"
9 #include "vframe.h"
12 #include <libintl.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());
38         return 1;
45 TimeStretchFreq::TimeStretchFreq(TimeStretch *plugin, 
46         TimeStretchWindow *gui, 
47         int x, 
48         int y)
49  : BC_Radial(x, y, plugin->use_fft, _("Use fast fourier transform"))
51         this->plugin = plugin;
52         this->gui = gui;
55 int TimeStretchFreq::handle_event()
57         plugin->use_fft = 1;
58         update(1);
59         gui->time->update(0);
67 TimeStretchTime::TimeStretchTime(TimeStretch *plugin, 
68         TimeStretchWindow *gui, 
69         int x, 
70         int y)
71  : BC_Radial(x, y, !plugin->use_fft, _("Use overlapping windows"))
73         this->plugin = plugin;
74         this->gui = gui;
77 int TimeStretchTime::handle_event()
79         plugin->use_fft = 0;
80         update(1);
81         gui->freq->update(0);
95 TimeStretchWindow::TimeStretchWindow(TimeStretch *plugin, int x, int y)
96  : BC_Window(PROGRAM_NAME ": Time stretch", 
97                                 x - 160,
98                                 y - 75,
99                                 320, 
100                                 150, 
101                                 320, 
102                                 150,
103                                 0,
104                                 0,
105                                 1)
107         this->plugin = plugin;
111 TimeStretchWindow::~TimeStretchWindow()
115 void TimeStretchWindow::create_objects()
117         int x = 10, y = 10;
119         add_subwindow(new BC_Title(x, y, _("Fraction of original length:")));
120         y += 20;
121         add_subwindow(new TimeStretchFraction(plugin, x, y));
123         y += 30;
124         add_subwindow(freq = new TimeStretchFreq(plugin, this, x, y));
125         y += 20;
126         add_subwindow(time = new TimeStretchTime(plugin, this, x, y));
128         add_subwindow(new BC_OKButton(this));
129         add_subwindow(new BC_CancelButton(this));
130         show_window();
134         flush();
146 PitchEngine::PitchEngine(TimeStretch *plugin)
147  : CrossfadeFFT()
149         this->plugin = plugin;
153 int PitchEngine::signal_process()
156         int min_freq = 
157                 1 + (int)(20.0 / ((double)plugin->PluginAClient::project_sample_rate / window_size * 2) + 0.5);
159         if(plugin->scale < 1)
160         {
161                 for(int i = min_freq; i < window_size / 2; i++)
162                 {
163                         double destination = i * plugin->scale;
164                         int dest_i = (int)(destination + 0.5);
165                         if(dest_i != i)
166                         {
167                                 if(dest_i <= window_size / 2)
168                                 {
169                                         freq_real[dest_i] = freq_real[i];
170                                         freq_imag[dest_i] = freq_imag[i];
171                                 }
172                                 freq_real[i] = 0;
173                                 freq_imag[i] = 0;
174                         }
175                 }
176         }
177         else
178         if(plugin->scale > 1)
179         {
180 //printf("PitchEngine::signal_process 1\n");
181                 for(int i = window_size / 2 - 1; i >= min_freq; i--)
182                 {
183                         double destination = i * plugin->scale;
184                         int dest_i = (int)(destination + 0.5);
185                         if(dest_i != i)
186                         {
187                                 if(dest_i <= window_size / 2)
188                                 {
189                                         freq_real[dest_i] = freq_real[i];
190                                         freq_imag[dest_i] = freq_imag[i];
191                                 }
192                                 freq_real[i] = 0;
193                                 freq_imag[i] = 0;
194                         }
195                 }
196 //printf("PitchEngine::signal_process 1\n");
197         }
199         symmetry(window_size, freq_real, freq_imag);
200 //printf("PitchEngine::signal_process 2\n");
201         return 0;
217 TimeStretch::TimeStretch(PluginServer *server)
218  : PluginAClient(server)
220         load_defaults();
221         temp = 0;
222         pitch = 0;
223         resample = 0;
224         stretch = 0;
225         input = 0;
226         input_allocated = 0;
230 TimeStretch::~TimeStretch()
232         save_defaults();
233         delete defaults;
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;
241         
242         
243 char* TimeStretch::plugin_title()
245         return _("Time stretch");
248 int TimeStretch::get_parameters()
250         BC_DisplayInfo info;
251         TimeStretchWindow window(this, info.get_abs_cursor_x(), info.get_abs_cursor_y());
252         window.create_objects();
253         int result = window.run_window();
254         
255         return result;
258 VFrame* TimeStretch::new_picon()
260         return new VFrame(picon_png);
264 int TimeStretch::start_loop()
266         if(PluginClient::interactive)
267         {
268                 char string[BCTEXTLEN];
269                 sprintf(string, "%s...", plugin_title());
270                 progress = start_progress(string, 
271                         (int64_t)((double)(PluginClient::end - PluginClient::start) * scale));
272         }
274         current_position = PluginClient::start;
275         total_written = 0;
279 // The FFT case
280         if(use_fft)
281         {
282                 pitch = new PitchEngine(this);
283                 pitch->initialize(WINDOW_SIZE);
284                 resample = new Resample(0, 1);
285         }
286         else
287 // The windowing case
288         {
289 // Must be short enough to mask beating but long enough to mask humming.
290                 stretch = new TimeStretchEngine(scale, PluginAClient::project_sample_rate);
291         }
295         
296         return 0;
299 int TimeStretch::stop_loop()
301         if(PluginClient::interactive)
302         {
303                 progress->stop_progress();
304                 delete progress;
305         }
306         return 0;
309 int TimeStretch::process_loop(double *buffer, int64_t &write_length)
311 //printf("TimeStretch::process_loop 1\n");
312         int result = 0;
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)
319         {
320                 if(input) delete [] input;
321                 input = new double[size];
322                 input_allocated = size;
323         }
325         read_samples(input, 0, current_position, size);
326         current_position += size;
329 // The FFT case
330         if(use_fft)
331         {
333                 resample->resample_chunk(input, 
334                         size, 
335                         1000000, 
336                         (int)(1000000.0 * scale), 
337                         0);
340                 if(resample->get_output_size(0))
341                 {
342                         int64_t output_size = resample->get_output_size(0);
343                         if(temp && temp_allocated < output_size)
344                         {
345                                 delete [] temp;
346                                 temp = 0;
347                         }
349                         if(!temp)
350                         {
351                                 temp = new double[output_size];
352                                 temp_allocated = output_size;
353                         }
354                         resample->read_output(temp, 0, output_size);
357                         samples_rendered = pitch->process_fifo(output_size, 
358                                 temp, 
359                                 buffer);
362                 }
363         }
364         else
365 // The windowing case
366         {
367 //printf("TimeStretch::process_loop 10\n");
368                 samples_rendered = stretch->process(input, size);
369 //printf("TimeStretch::process_loop 20 %d\n", samples_rendered);
370                 if(samples_rendered)
371                 {
372                         samples_rendered = MIN(samples_rendered, PluginAClient::in_buffer_size);
373                         stretch->read_output(buffer, samples_rendered);
374                 }
375 //printf("TimeStretch::process_loop 30\n");
376         }
379         if(samples_rendered)
380         {
381                 total_written += samples_rendered;
382         }
384 // Trim output to predicted length of stretched selection.
385         if(total_written > predicted_total)
386         {
387                 samples_rendered -= total_written - predicted_total;
388                 result = 1;
389         }
392         write_length = samples_rendered;
393         if(PluginClient::interactive) result = progress->update(total_written);
394 //printf("TimeStretch::process_loop 100\n");
396         return result;
401 int TimeStretch::load_defaults()
403         char directory[BCTEXTLEN];
405 // set the default directory
406         sprintf(directory, "%stimestretch.rc", BCASTDIR);
407 // load the defaults
408         defaults = new Defaults(directory);
409         defaults->load();
411         scale = defaults->get("SCALE", (double)1);
412         use_fft = defaults->get("USE_FFT", 0);
413         return 0;
416 int TimeStretch::save_defaults()
418         defaults->update("SCALE", scale);
419         defaults->update("USE_FFT", use_fft);
420         defaults->save();
421         return 0;