lpcm with tsmuxer cleanup by Andrew
[goodguy/cinelerra.git] / cinelerra-5.1 / plugins / speed_pc / speed_pc.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2016 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 /*
23  * 2020. Derivative by ReframeRT plugin for a more easy use.
24  * It uses percentage value of the speed referred to originl speed (=100%).
25  * Some old ReframeRT parameters (Stretch and denom) have not been deleted,
26  * for future development, if any.
27  * Stretch and denom variables are set to a constant value:
28  * Stretch= 1; denom= 100.00.
29  * Speed_MIN= 1.00%; Speed_MAX= 1000.00% 
30  */
31
32 #include "bcdisplayinfo.h"
33 #include "clip.h"
34 #include "bchash.h"
35 #include "filexml.h"
36 #include "speed_pc.h"
37 #include "guicast.h"
38 #include "language.h"
39 #include "pluginvclient.h"
40 #include "theme.h"
41 #include "transportque.h"
42
43 #include <string.h>
44
45
46
47
48 REGISTER_PLUGIN(SpeedPc);
49
50
51
52 SpeedPcConfig::SpeedPcConfig()
53 {
54         reset(RESET_DEFAULT_SETTINGS);
55 }
56
57 void SpeedPcConfig::reset(int clear)
58 {
59         switch(clear) {
60                 case RESET_SPEED :
61                         num = 100.00;
62                         denom = 100.0;
63                         stretch = 1;
64                         break;
65                 case RESET_ALL :
66                 case RESET_DEFAULT_SETTINGS :
67                 default:
68                         num = 100.00;
69                         denom = 100.0;
70                         stretch = 1;
71                         interp = 0;
72                         optic_flow = 1;
73                         break;
74         }
75 }
76
77 int SpeedPcConfig::equivalent(SpeedPcConfig &src)
78 {
79         return fabs(num - src.num) < 0.0001 &&
80                 fabs(denom - src.denom) < 0.0001 &&
81                 stretch == src.stretch &&
82                 interp == src.interp;
83 }
84
85 void SpeedPcConfig::copy_from(SpeedPcConfig &src)
86 {
87         this->num = src.num;
88         this->denom = src.denom;
89         this->stretch = src.stretch;
90         this->interp = src.interp;
91 }
92
93 void SpeedPcConfig::interpolate(SpeedPcConfig &prev,
94         SpeedPcConfig &next,
95         int64_t prev_frame,
96         int64_t next_frame,
97         int64_t current_frame)
98 {
99         this->interp = prev.interp;
100         this->stretch = prev.stretch;
101         this->denom = prev.denom;
102
103         if (this->interp && prev_frame != next_frame)
104         {
105                 double next_weight = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
106                 double prev_weight = (double)(next_frame - current_frame) / (next_frame - prev_frame);
107                 double prev_slope = prev.num / prev.denom, next_slope = next.num / next.denom;
108                 // for interpolation, this is (for now) a simple linear slope to the next keyframe.
109                 double scale = prev_slope * prev_weight + next_slope * next_weight;
110                 this->num = this->denom * scale;
111         }
112         else
113         {
114                 this->num = prev.num;
115         }
116 }
117
118 void SpeedPcConfig::boundaries()
119 {
120         if(num < 0.0001) num = 0.0001;
121         if(denom < 0.0001) denom = 0.0001;
122 }
123
124
125
126
127
128
129
130
131 SpeedPcWindow::SpeedPcWindow(SpeedPc *plugin)
132  : PluginClientWindow(plugin, xS(420), yS(150), xS(420), yS(150), 0)  // Note: with "Stretch" and "Downsample" gui yS was yS(210)
133 {
134         this->plugin = plugin;
135 }
136
137 SpeedPcWindow::~SpeedPcWindow()
138 {
139 }
140
141 void SpeedPcWindow::create_objects()
142 {
143         int xs10 = xS(10), xs64 = xS(64), xs200 = xS(200);
144         int ys10 = yS(10), ys30 = yS(30), ys40 = yS(40);
145         int x2 = xS(80), x3 = xS(180);
146         int x = xs10, y = ys10;
147         int clr_x = get_w()-x - xS(22); // note: clrBtn_w = 22
148
149         BC_Bar *bar;
150
151         add_subwindow(new BC_Title(x, y, _("Preset:")));
152         x = x + x2; 
153         add_subwindow(toggle25pc = new SpeedPcToggle(plugin, this,
154                 plugin->config.num == 25, x, y, 25, "25%"));
155         x += xs64;
156         add_subwindow(toggle50pc = new SpeedPcToggle(plugin, this,
157                 plugin->config.num == 50, x, y, 50, "50%"));
158         x += xs64;
159         add_subwindow(toggle100pc = new SpeedPcToggle(plugin, this,
160                 plugin->config.num == 100, x, y, 100, "100%"));
161         x += xs64;
162         add_subwindow(toggle200pc = new SpeedPcToggle(plugin, this,
163                 plugin->config.num == 200, x, y, 200, "200%"));
164         x += xs64;
165         add_subwindow(toggle400pc = new SpeedPcToggle(plugin, this,
166                 plugin->config.num == 400, x, y, 400, "400%"));
167         x = xs10;  y += ys30;
168
169         add_tool(new BC_Title(x, y, _("Speed:")));
170         add_tool(new BC_Title((x2-x), y, _("%")));
171         speed_pc_text = new SpeedPcText(plugin, this, (x + x2), y);
172         speed_pc_text->create_objects();
173         speed_pc_slider = new SpeedPcSlider(plugin, this, x3, y, xs200);
174         add_subwindow(speed_pc_slider);
175         clr_x = x3 + speed_pc_slider->get_w() + x;
176         add_subwindow(speed_pc_clr = new SpeedPcClr(plugin, this,
177                 clr_x, y, RESET_SPEED));
178         y += ys30;
179
180 // REM 2020-06-23
181 /*
182         add_subwindow(stretch = new SpeedPcStretch(plugin, this, x, y));
183         y += yS(30);
184         add_subwindow(downsample = new SpeedPcDownsample(plugin, this, x, y));
185         y += yS(30);
186 */
187
188         add_subwindow(interpolate = new SpeedPcInterpolate(plugin, this, x, y));
189         y += ys40;
190
191 // Reset section
192         add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
193         y += ys10;
194         add_subwindow(reset = new SpeedPcReset(plugin, this, x, y));
195
196         update(RESET_ALL);
197         show_window();
198 }
199
200 void SpeedPcWindow::update(int clear)
201 {
202         switch(clear) {
203                 case RESET_SPEED :
204                         speed_pc_text->update((float)plugin->config.num);
205                         speed_pc_slider->update((float)plugin->config.num);
206                         update_toggles();
207                         break;
208                 case RESET_ALL :
209                 case RESET_DEFAULT_SETTINGS :
210                 default:
211                         speed_pc_text->update((float)plugin->config.num);
212                         speed_pc_slider->update((float)plugin->config.num);
213                         update_toggles();
214
215 // OLD ReframeRT code
216 /*
217                         stretch->update(plugin->config.stretch);
218                         downsample->update(!plugin->config.stretch);
219 */
220                         interpolate->update(plugin->config.interp);
221                         break;
222         }
223 }
224
225
226 int SpeedPcWindow::update_toggles()
227 {
228         toggle25pc->update(EQUIV(plugin->config.num, 25));
229         toggle50pc->update(EQUIV(plugin->config.num, 50));
230         toggle100pc->update(EQUIV(plugin->config.num, 100));
231         toggle200pc->update(EQUIV(plugin->config.num, 200));
232         toggle400pc->update(EQUIV(plugin->config.num, 400));
233         return 0;
234 }
235
236
237 SpeedPcToggle::SpeedPcToggle(SpeedPc *plugin, SpeedPcWindow *gui,
238         int init_value,
239         int x,
240         int y,
241         int value,
242         const char *string)
243  : BC_Radial(x, y, init_value, string)
244 {
245         this->value = value;
246         this->plugin = plugin;
247         this->gui = gui;
248 }
249
250 int SpeedPcToggle::handle_event()
251 {
252         plugin->config.num = (float)value;
253         gui->update(RESET_SPEED);
254         plugin->send_configure_change();
255         return 1;
256 }
257
258
259
260 /* *********************************** */
261 /* **** SPEED     ******************** */
262 SpeedPcText::SpeedPcText(SpeedPc *plugin, SpeedPcWindow *gui,
263         int x,
264         int y)
265  : BC_TumbleTextBox(gui, (float)plugin->config.num,
266         (float)1.00, (float)1000.00, x, y, xS(60), 2)
267 {
268         this->plugin = plugin;
269         this->gui = gui;
270 }
271
272 SpeedPcText::~SpeedPcText()
273 {
274 }
275
276 int SpeedPcText::handle_event()
277 {
278         plugin->config.num = atof(get_text());
279         plugin->config.denom = 100.00;
280         plugin->config.stretch = 1;
281         plugin->config.boundaries();
282         gui->update(RESET_SPEED);
283         plugin->send_configure_change();
284         return 1;
285 }
286
287 SpeedPcSlider::SpeedPcSlider(SpeedPc *plugin, SpeedPcWindow *gui,
288         int x, int y, int w)
289  : BC_FSlider(x, y, 0, w, w, 1.00, 1000.00, plugin->config.num)
290 {
291         this->plugin = plugin;
292         this->gui = gui;
293         enable_show_value(0); // Hide caption
294         set_precision(1.00);
295 }
296
297 SpeedPcSlider::~SpeedPcSlider()
298 {
299 }
300
301 int SpeedPcSlider::handle_event()
302 {
303         plugin->config.num = get_value();
304         plugin->config.denom = 100.00;
305         plugin->config.stretch = 1;
306         gui->update(RESET_SPEED);
307         plugin->send_configure_change();
308         return 1;
309 }
310 /* *********************************** */
311
312
313 SpeedPcStretch::SpeedPcStretch(SpeedPc *plugin,
314         SpeedPcWindow *gui,
315         int x,
316         int y)
317  : BC_Radial(x, y, plugin->config.stretch, _("Stretch"))
318 {
319         this->plugin = plugin;
320         this->gui = gui;
321 }
322
323 int SpeedPcStretch::handle_event()
324 {
325         plugin->config.stretch = get_value();
326         gui->downsample->update(!get_value());
327         plugin->send_configure_change();
328         return 1;
329 }
330
331
332 SpeedPcDownsample::SpeedPcDownsample(SpeedPc *plugin, SpeedPcWindow *gui,
333         int x,
334         int y)
335  : BC_Radial(x, y, !plugin->config.stretch, _("Downsample"))
336 {
337         this->plugin = plugin;
338         this->gui = gui;
339 }
340
341 int SpeedPcDownsample::handle_event()
342 {
343         plugin->config.stretch = !get_value();
344         gui->stretch->update(!get_value());
345         plugin->send_configure_change();
346         return 1;
347 }
348
349 SpeedPcInterpolate::SpeedPcInterpolate(SpeedPc *plugin, SpeedPcWindow *gui,
350         int x,
351         int y)
352  : BC_CheckBox(x, y, 0, _("Interpolate"))
353 {
354         this->plugin = plugin;
355         this->gui = gui;
356         set_tooltip(_("Interpolate between keyframes"));
357 }
358
359 int SpeedPcInterpolate::handle_event()
360 {
361         plugin->config.interp = get_value();
362         gui->interpolate->update(get_value());
363         plugin->send_configure_change();
364         return 1;
365 }
366
367
368 SpeedPcClr::SpeedPcClr(SpeedPc *plugin, SpeedPcWindow *gui, int x, int y, int clear)
369  : BC_Button(x, y, plugin->get_theme()->get_image_set("reset_button"))
370 {
371         this->plugin = plugin;
372         this->gui = gui;
373         this->clear = clear;
374 }
375 SpeedPcClr::~SpeedPcClr()
376 {
377 }
378 int SpeedPcClr::handle_event()
379 {
380         plugin->config.reset(clear);
381         gui->update(clear);
382         plugin->send_configure_change();
383         return 1;
384 }
385
386
387 SpeedPcReset::SpeedPcReset(SpeedPc *plugin, SpeedPcWindow *gui, int x, int y)
388  : BC_GenericButton(x, y, _("Reset"))
389 {
390         this->plugin = plugin;
391         this->gui = gui;
392 }
393 SpeedPcReset::~SpeedPcReset()
394 {
395 }
396 int SpeedPcReset::handle_event()
397 {
398         plugin->config.reset(RESET_ALL);
399         gui->update(RESET_ALL);
400         plugin->send_configure_change();
401         return 1;
402 }
403
404
405
406 SpeedPc::SpeedPc(PluginServer *server)
407  : PluginVClient(server)
408 {
409 }
410
411 SpeedPc::~SpeedPc()
412 {
413
414 }
415
416 const char* SpeedPc::plugin_title() { return N_("Speed PerCent"); }
417 int SpeedPc::is_realtime() { return 1; }
418 int SpeedPc::is_synthesis() { return 1; }
419
420
421 NEW_WINDOW_MACRO(SpeedPc, SpeedPcWindow)
422 LOAD_CONFIGURATION_MACRO(SpeedPc, SpeedPcConfig)
423
424 int SpeedPc::process_buffer(VFrame *frame,
425                 int64_t start_position,
426                 double frame_rate)
427 {
428         int64_t input_frame = get_source_start();
429         SpeedPcConfig prev_config, next_config;
430         KeyFrame *tmp_keyframe, *next_keyframe = get_prev_keyframe(get_source_start());
431         int64_t tmp_position, next_position;
432         int64_t segment_len;
433         double input_rate = frame_rate;
434         int is_current_keyframe;
435
436 // if there are no keyframes, the default keyframe is used, and its position is always 0;
437 // if there are keyframes, the first keyframe can be after the effect start (and it controls settings before it)
438 // so let's calculate using a fake keyframe with the same settings but position == effect start
439         KeyFrame *fake_keyframe = new KeyFrame();
440         fake_keyframe->copy_from(next_keyframe);
441         fake_keyframe->position = local_to_edl(get_source_start());
442         next_keyframe = fake_keyframe;
443
444         // calculate input_frame accounting for all previous keyframes
445         do
446         {
447                 tmp_keyframe = next_keyframe;
448                 next_keyframe = get_next_keyframe(tmp_keyframe->position+1, 0);
449
450                 tmp_position = edl_to_local(tmp_keyframe->position);
451                 next_position = edl_to_local(next_keyframe->position);
452
453                 is_current_keyframe =
454                         next_position > start_position // the next keyframe is after the current position
455                         || next_keyframe->position == tmp_keyframe->position // there are no more keyframes
456                         || !next_keyframe->position; // there are no keyframes at all
457
458                 if (is_current_keyframe)
459                         segment_len = start_position - tmp_position;
460                 else
461                         segment_len = next_position - tmp_position;
462
463                 read_data(next_keyframe);
464                 next_config.copy_from(config);
465                 read_data(tmp_keyframe);
466                 prev_config.copy_from(config);
467                 config.interpolate(prev_config, next_config, tmp_position, next_position, tmp_position + segment_len);
468
469                 // the area under the curve is the number of frames to advance
470                 // as long as interpolate() uses a linear slope we can use geometry to determine this
471                 // if interpolate() changes to use a curve then this needs use (possibly) the definite integral
472                 double prev_scale = prev_config.num / 100.00;
473                 double config_scale = config.num / 100.00;
474                 input_frame += (int64_t)(segment_len * ((prev_scale + config_scale) / 2));
475         } while (!is_current_keyframe);
476
477 // Change rate
478         if (!config.stretch)
479         {
480                 input_rate *= config.num / 100.00;
481
482         }
483
484 // printf("SpeedPc::process_buffer %d %lld %f %lld %f\n",
485 // __LINE__,
486 // start_position,
487 // frame_rate,
488 // input_frame,
489 // input_rate);
490
491         read_frame(frame,
492                 0,
493                 input_frame,
494                 input_rate,
495                 0);
496
497         delete fake_keyframe;
498
499         return 0;
500 }
501
502
503
504 void SpeedPc::save_data(KeyFrame *keyframe)
505 {
506         FileXML output;
507
508 // cause data to be stored directly in text
509         output.set_shared_output(keyframe->xbuf);
510         output.tag.set_title("SPEED_PC");
511         output.tag.set_property("SPEED", config.num);
512         output.tag.set_property("DENOM", config.denom);
513         output.tag.set_property("STRETCH", config.stretch);
514         output.tag.set_property("INTERPOLATE", config.interp);
515         output.append_tag();
516         output.tag.set_title("/SPEED_PC");
517         output.append_tag();
518         output.append_newline();
519         output.terminate_string();
520 }
521
522 void SpeedPc::read_data(KeyFrame *keyframe)
523 {
524         FileXML input;
525
526         input.set_shared_input(keyframe->xbuf);
527
528         while(!input.read_tag())
529         {
530                 if(input.tag.title_is("SPEED_PC"))
531                 {
532                         config.num = input.tag.get_property("SPEED", config.num);
533                         config.denom = input.tag.get_property("DENOM", config.denom);
534                         config.stretch = input.tag.get_property("STRETCH", config.stretch);
535                         config.interp = input.tag.get_property("INTERPOLATE", config.interp);
536                 }
537         }
538 }
539
540 void SpeedPc::update_gui()
541 {
542         if(thread)
543         {
544                 int changed = load_configuration();
545
546                 if(changed)
547                 {
548                         SpeedPcWindow* window = (SpeedPcWindow*)thread->window;
549                         window->lock_window("SpeedPc::update_gui");
550                         window->update(RESET_ALL);
551 // OLD ReframeRT code
552 /*
553                         window->stretch->update(config.stretch);
554                         window->downsample->update(!config.stretch);
555 */
556                         window->unlock_window();
557                 }
558         }
559 }
560
561
562
563
564