Merge CV, ver=5.1; ops/methods from HV, and interface from CV where possible
[goodguy/history.git] / cinelerra-5.1 / cinelerra / menueffects.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2010 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 #include "asset.h"
23 #include "awindow.h"
24 #include "awindowgui.h"
25 #include "clip.h"
26 #include "confirmsave.h"
27 #include "bchash.h"
28 #include "edl.h"
29 #include "edlsession.h"
30 #include "errorbox.h"
31 #include "file.h"
32 #include "formatcheck.h"
33 #include "indexfile.h"
34 #include "keyframe.h"
35 #include "keys.h"
36 #include "labels.h"
37 #include "language.h"
38 #include "loadmode.h"
39 #include "localsession.h"
40 #include "mainmenu.h"
41 #include "mainsession.h"
42 #include "mainundo.h"
43 #include "mwindow.h"
44 #include "mwindowgui.h"
45 #include "menueffects.h"
46 #include "playbackengine.h"
47 #include "pluginarray.h"
48 #include "pluginserver.h"
49 #include "preferences.h"
50 #include "render.h"
51 #include "sighandler.h"
52 #include "theme.h"
53 #include "tracks.h"
54
55
56
57 MenuEffects::MenuEffects(MWindow *mwindow)
58  : BC_MenuItem(_("Render effect..."))
59 {
60         this->mwindow = mwindow;
61 }
62
63 MenuEffects::~MenuEffects()
64 {
65 }
66
67
68 int MenuEffects::handle_event()
69 {
70         thread->set_title("");
71         thread->start();
72         return 1;
73 }
74
75
76
77
78
79 MenuEffectPacket::MenuEffectPacket(char *path, int64_t start, int64_t end)
80 {
81         this->start = start;
82         this->end = end;
83         strcpy(this->path, path);
84 }
85
86 MenuEffectPacket::~MenuEffectPacket()
87 {
88 }
89
90
91
92
93
94
95 MenuEffectThread::MenuEffectThread(MWindow *mwindow, MenuEffects *menu_item)
96 {
97         this->mwindow = mwindow;
98         this->menu_item = menu_item;
99         title[0] = 0;
100         dead_plugins = new ArrayList<PluginServer*>;
101 }
102
103 MenuEffectThread::~MenuEffectThread()
104 {
105         delete dead_plugins;
106 }
107
108
109
110
111
112 int MenuEffectThread::set_title(const char *title)
113 {
114         strcpy(this->title, title);
115         return 0;
116 }
117
118 // for recent effect menu items and running new effects
119 // prompts for an effect if title is blank
120 void MenuEffectThread::run()
121 {
122         for(int i = 0; i < dead_plugins->size(); i++)
123         {
124                 delete dead_plugins->get(i);
125         }
126         dead_plugins->remove_all();
127
128
129
130
131 // get stuff from main window
132         ArrayList<PluginServer*> *plugindb = mwindow->plugindb;
133         BC_Hash *defaults = mwindow->defaults;
134         ArrayList<BC_ListBoxItem*> plugin_list;
135         ArrayList<PluginServer*> local_plugindb;
136         char string[1024];
137         int result = 0;
138 // Default configuration
139         Asset *default_asset = new Asset;
140 // Output
141         ArrayList<Indexable*> assets;
142
143
144 // check for recordable tracks
145         if(!get_recordable_tracks(default_asset))
146         {
147                 sprintf(string, _("No recordable tracks specified."));
148                 ErrorBox error(_(PROGRAM_NAME ": Error"));
149                 error.create_objects(string);
150                 error.run_window();
151                 default_asset->Garbage::remove_user();
152                 return;
153         }
154
155 // check for plugins
156         if(!plugindb->total)
157         {
158                 sprintf(string, _("No plugins available."));
159                 ErrorBox error(_(PROGRAM_NAME ": Error"));
160                 error.create_objects(string);
161                 error.run_window();
162                 default_asset->Garbage::remove_user();
163                 return;
164         }
165
166
167 // get default attributes for output file
168 // used after completion
169         get_derived_attributes(default_asset, defaults);
170 //      to_tracks = defaults->get("RENDER_EFFECT_TO_TRACKS", 1);
171         load_mode = defaults->get("RENDER_EFFECT_LOADMODE", LOADMODE_PASTE);
172         strategy = defaults->get("RENDER_EFFECT_STRATEGY", SINGLE_PASS);
173
174 // get plugin information
175         int need_plugin;
176         if(!strlen(title))
177                 need_plugin = 1;
178         else
179                 need_plugin = 0;
180
181 // generate a list of plugins for the window
182         if(need_plugin)
183         {
184                 mwindow->search_plugindb(default_asset->audio_data,
185                         default_asset->video_data,
186                         -1,
187                         0,
188                         0,
189                         local_plugindb);
190
191                 for(int i = 0; i < local_plugindb.total; i++)
192                 {
193                         plugin_list.append(new BC_ListBoxItem(_(local_plugindb.values[i]->title)));
194                 }
195         }
196
197 // find out which effect to run and get output file
198         int plugin_number, format_error = 0;
199
200         do
201         {
202                 {
203                         MenuEffectWindow window(mwindow,
204                                 this,
205                                 need_plugin ? &plugin_list : 0,
206                                 default_asset);
207                         window.create_objects();
208                         result = window.run_window();
209                         plugin_number = window.result;
210                 }
211
212                 if(!result)
213                 {
214                         FormatCheck format_check(default_asset);
215                         format_error = format_check.check_format();
216                 }
217         }while(format_error && !result);
218
219 // save defaults
220         save_derived_attributes(default_asset, defaults);
221         defaults->update("RENDER_EFFECT_LOADMODE", load_mode);
222         defaults->update("RENDER_EFFECT_STRATEGY", strategy);
223         mwindow->save_defaults();
224
225 // get plugin server to use and delete the plugin list
226         PluginServer *plugin_server = 0;
227         PluginServer *plugin = 0;
228         if(need_plugin)
229         {
230                 plugin_list.remove_all_objects();
231                 if(plugin_number > -1)
232                 {
233                         plugin_server = local_plugindb.values[plugin_number];
234                         strcpy(title, plugin_server->title);
235                 }
236         }
237         else
238         {
239                 for(int i = 0; i < plugindb->total && !plugin_server; i++)
240                 {
241                         if(!strcmp(plugindb->values[i]->title, title))
242                         {
243                                 plugin_server = plugindb->values[i];
244                                 plugin_number = i;
245                         }
246                 }
247         }
248
249 // Update the  most recently used effects and copy the plugin server.
250         if(plugin_server)
251         {
252                 plugin = new PluginServer(*plugin_server);
253                 fix_menu(title);
254         }
255
256         if(!result && !strlen(default_asset->path))
257         {
258                 result = 1;        // no output path given
259                 ErrorBox error(_(PROGRAM_NAME ": Error"));
260                 error.create_objects(_("No output file specified."));
261                 error.run_window();
262         }
263
264         if(!result && plugin_number < 0)
265         {
266                 result = 1;        // no output path given
267                 ErrorBox error(_(PROGRAM_NAME ": Error"));
268                 error.create_objects(_("No effect selected."));
269                 error.run_window();
270         }
271
272 // Configuration for realtime plugins.
273         KeyFrame plugin_data;
274
275 // get selection to render
276 // Range
277         double total_start, total_end;
278
279         total_start = mwindow->edl->local_session->get_selectionstart();
280
281
282         if(mwindow->edl->local_session->get_selectionend() ==
283                 mwindow->edl->local_session->get_selectionstart())
284                 total_end = mwindow->edl->tracks->total_playable_length();
285         else
286                 total_end = mwindow->edl->local_session->get_selectionend();
287
288
289
290 // get native units for range
291         total_start = to_units(total_start, 0);
292         total_end = to_units(total_end, 1);
293
294
295
296 // Trick boundaries in case of a non-realtime synthesis plugin
297         if(plugin &&
298                 !plugin->realtime &&
299                 total_end == total_start) total_end = total_start + 1;
300
301 // Units are now in the track's units.
302         int64_t total_length = (int64_t)total_end - (int64_t)total_start;
303 // length of output file
304
305         if(!result && total_length <= 0)
306         {
307                 result = 1;        // no output path given
308                 ErrorBox error(_(PROGRAM_NAME ": Error"));
309                 error.create_objects(_("No selected range to process."));
310                 error.run_window();
311         }
312
313 // ========================= get keyframe from user
314         if(!result)
315         {
316 // ========================= realtime plugin
317 // no get_parameters
318                 if(plugin->realtime)
319                 {
320 // Open a prompt GUI
321                         MenuEffectPrompt prompt(mwindow);
322                         prompt.create_objects();
323                         char title[BCTEXTLEN];
324                         sprintf(title, _(PROGRAM_NAME ": %s"), plugin->title);
325
326 // Open the plugin GUI
327                         plugin->set_mwindow(mwindow);
328                         plugin->set_keyframe(&plugin_data);
329                         plugin->set_prompt(&prompt);
330                         plugin->open_plugin(0, mwindow->preferences, mwindow->edl, 0);
331 // Must set parameters since there is no plugin object to draw from.
332                         plugin->get_parameters((int64_t)total_start,
333                                 (int64_t)total_end,
334                                 1);
335                         plugin->show_gui();
336
337 // wait for user input
338                         result = prompt.run_window();
339
340 // Close plugin.
341                         plugin->save_data(&plugin_data);
342                         plugin->hide_gui();
343
344 // Can't delete here.
345                         dead_plugins->append(plugin);
346                         default_asset->sample_rate = mwindow->edl->session->sample_rate;
347                         default_asset->frame_rate = mwindow->edl->session->frame_rate;
348                         realtime = 1;
349                 }
350                 else
351 // ============================non realtime plugin
352                 {
353                         plugin->set_mwindow(mwindow);
354                         plugin->open_plugin(0, mwindow->preferences, mwindow->edl, 0);
355                         result = plugin->get_parameters((int64_t)total_start,
356                                 (int64_t)total_end,
357                                 get_recordable_tracks(default_asset));
358 // some plugins can change the sample rate and the frame rate
359
360
361                         if(!result)
362                         {
363                                 default_asset->sample_rate = plugin->get_samplerate();
364                                 default_asset->frame_rate = plugin->get_framerate();
365                         }
366                         delete plugin;
367                         realtime = 0;
368                 }
369
370 // Should take from first recordable track
371                 default_asset->width = mwindow->edl->session->output_w;
372                 default_asset->height = mwindow->edl->session->output_h;
373         }
374
375 // Process the total length in fragments
376         ArrayList<MenuEffectPacket*> packets;
377         if(!result)
378         {
379                 Label *current_label = mwindow->edl->labels->first;
380                 mwindow->stop_brender();
381
382                 int current_number;
383                 int number_start;
384                 int total_digits;
385                 Render::get_starting_number(default_asset->path,
386                         current_number,
387                         number_start,
388                         total_digits);
389
390
391
392 // Construct all packets for single overwrite confirmation
393                 for(int64_t fragment_start = (int64_t)total_start, fragment_end;
394                         fragment_start < (int64_t)total_end;
395                         fragment_start = fragment_end)
396                 {
397 // Get fragment end
398                         if(strategy == FILE_PER_LABEL || strategy == FILE_PER_LABEL_FARM)
399                         {
400                                 while(current_label  &&
401                                         to_units(current_label->position, 0) <= fragment_start)
402                                         current_label = current_label->next;
403                                 if(!current_label)
404                                         fragment_end = (int64_t)total_end;
405                                 else
406                                         fragment_end = to_units(current_label->position, 0);
407                         }
408                         else
409                         {
410                                 fragment_end = (int64_t)total_end;
411                         }
412
413 // Get path
414                         char path[BCTEXTLEN];
415                         if(strategy == FILE_PER_LABEL || strategy == FILE_PER_LABEL_FARM)
416                                 Render::create_filename(path,
417                                         default_asset->path,
418                                         current_number,
419                                         total_digits,
420                                         number_start);
421                         else
422                                 strcpy(path, default_asset->path);
423                         current_number++;
424
425                         MenuEffectPacket *packet = new MenuEffectPacket(path,
426                                 fragment_start,
427                                 fragment_end);
428                         packets.append(packet);
429                 }
430
431
432 // Test existence of files
433                 ArrayList<char*> paths;
434                 for(int i = 0; i < packets.total; i++)
435                 {
436                         paths.append(packets.values[i]->path);
437                 }
438                 result = ConfirmSave::test_files(mwindow, &paths);
439                 paths.remove_all();
440         }
441
442
443
444         for(int current_packet = 0;
445                 current_packet < packets.total && !result;
446                 current_packet++)
447         {
448                 Asset *asset = new Asset(*default_asset);
449                 MenuEffectPacket *packet = packets.values[current_packet];
450                 int64_t fragment_start = packet->start;
451                 int64_t fragment_end = packet->end;
452                 strcpy(asset->path, packet->path);
453
454                 assets.append(asset);
455                 File *file = new File;
456
457 // Open the output file after getting the information because the sample rate
458 // is needed here.
459                 if(!result)
460                 {
461 // open output file in write mode
462                         file->set_processors(mwindow->preferences->processors);
463                         if(file->open_file(mwindow->preferences,
464                                 asset,
465                                 0,
466                                 1))
467                         {
468 // open failed
469                                 sprintf(string, _("Couldn't open %s"), asset->path);
470                                 ErrorBox error(_(PROGRAM_NAME ": Error"));
471                                 error.create_objects(string);
472                                 error.run_window();
473                                 result = 1;
474                         }
475                         else
476                         {
477                                 mwindow->sighandler->push_file(file);
478                                 IndexFile::delete_index(mwindow->preferences,
479                                         asset);
480                         }
481                 }
482
483 // run plugins
484                 if(!result)
485                 {
486 // position file
487                         PluginArray *plugin_array;
488                         plugin_array = create_plugin_array();
489
490                         plugin_array->start_plugins(mwindow,
491                                 mwindow->edl,
492                                 plugin_server,
493                                 &plugin_data,
494                                 fragment_start,
495                                 fragment_end,
496                                 file);
497                         plugin_array->run_plugins();
498
499                         plugin_array->stop_plugins();
500                         mwindow->sighandler->pull_file(file);
501                         file->close_file();
502                         asset->audio_length = file->asset->audio_length;
503                         asset->video_length = file->asset->video_length;
504                         delete plugin_array;
505                 }
506
507                 delete file;
508         }
509
510         packets.remove_all_objects();
511
512 // paste output to tracks
513         if(!result && load_mode != LOADMODE_NOTHING)
514         {
515                 mwindow->gui->lock_window("MenuEffectThread::run");
516
517                 mwindow->undo->update_undo_before("", 0);
518                 if(load_mode == LOADMODE_PASTE)
519                         mwindow->clear(0);
520
521
522                 mwindow->load_assets(&assets,
523                         -1,
524                         load_mode,
525                         0,
526                         0,
527                         mwindow->edl->session->labels_follow_edits,
528                         mwindow->edl->session->plugins_follow_edits,
529                         mwindow->edl->session->autos_follow_edits,
530                         0); // overwrite
531
532                 mwindow->save_backup();
533                 mwindow->undo->update_undo_after(title, LOAD_ALL);
534
535
536
537                 mwindow->restart_brender();
538                 mwindow->update_plugin_guis();
539                 mwindow->gui->update(1,
540                         2,
541                         1,
542                         1,
543                         1,
544                         1,
545                         0);
546                 mwindow->sync_parameters(CHANGE_ALL);
547                 mwindow->gui->unlock_window();
548
549                 mwindow->awindow->gui->async_update_assets();
550         }
551
552         for(int i = 0; i < assets.total; i++)
553                 assets.values[i]->Garbage::remove_user();
554         assets.remove_all();
555
556         default_asset->Garbage::remove_user();
557 }
558
559
560
561
562
563
564
565 MenuEffectItem::MenuEffectItem(MenuEffects *menueffect, const char *string)
566  : BC_MenuItem(string)
567 {
568         this->menueffect = menueffect;
569 }
570 int MenuEffectItem::handle_event()
571 {
572         menueffect->thread->set_title(get_text());
573         menueffect->thread->start();
574         return 1;
575 }
576
577
578
579
580
581
582
583
584
585
586
587
588 MenuEffectWindow::MenuEffectWindow(MWindow *mwindow,
589         MenuEffectThread *menueffects,
590         ArrayList<BC_ListBoxItem*> *plugin_list,
591         Asset *asset)
592  : BC_Window(_(PROGRAM_NAME ": Render effect"),
593                 mwindow->gui->get_abs_cursor_x(1),
594                 mwindow->gui->get_abs_cursor_y(1) - mwindow->session->menueffect_h / 2,
595                 mwindow->session->menueffect_w,
596                 mwindow->session->menueffect_h,
597                 580,
598                 350,
599                 1,
600                 0,
601                 1)
602 {
603         this->menueffects = menueffects;
604         this->plugin_list = plugin_list;
605         this->asset = asset;
606         this->mwindow = mwindow;
607         file_title = 0;
608         format_tools = 0;
609         loadmode = 0;
610 }
611
612 MenuEffectWindow::~MenuEffectWindow()
613 {
614         lock_window("MenuEffectWindow::~MenuEffectWindow");
615         delete format_tools;
616         unlock_window();
617 }
618
619
620
621 void MenuEffectWindow::create_objects()
622 {
623         int x, y;
624         result = -1;
625         mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
626
627         lock_window("MenuEffectWindow::create_objects");
628 // only add the list if needed
629         if(plugin_list)
630         {
631                 add_subwindow(list_title = new BC_Title(mwindow->theme->menueffect_list_x,
632                         mwindow->theme->menueffect_list_y,
633                         _("Select an effect")));
634                 add_subwindow(list = new MenuEffectWindowList(this,
635                         mwindow->theme->menueffect_list_x,
636                         mwindow->theme->menueffect_list_y + list_title->get_h() + 5,
637                         mwindow->theme->menueffect_list_w,
638                         mwindow->theme->menueffect_list_h - list_title->get_h() - 5,
639                         plugin_list));
640         }
641
642         add_subwindow(file_title = new BC_Title(
643                 mwindow->theme->menueffect_file_x,
644                 mwindow->theme->menueffect_file_y,
645                 (char*)((menueffects->strategy == FILE_PER_LABEL  || menueffects->strategy == FILE_PER_LABEL_FARM) ?
646                         _("Select the first file to render to:") :
647                         _("Select a file to render to:"))));
648
649         x = mwindow->theme->menueffect_tools_x;
650         y = mwindow->theme->menueffect_tools_y;
651         format_tools = new FormatTools(mwindow,
652                                         this,
653                                         asset);
654         format_tools->create_objects(x,
655                                         y,
656                                         asset->audio_data,
657                                         asset->video_data,
658                                         0,
659                                         0,
660                                         0,
661                                         1,
662                                         0,
663                                         0,
664                                         &menueffects->strategy,
665                                         0);
666
667         loadmode = new LoadMode(mwindow, this, x, y, &menueffects->load_mode, 1);
668         loadmode->create_objects();
669
670         add_subwindow(new MenuEffectWindowOK(this));
671         add_subwindow(new MenuEffectWindowCancel(this));
672         show_window();
673         unlock_window();
674 }
675
676 int MenuEffectWindow::resize_event(int w, int h)
677 {
678         mwindow->session->menueffect_w = w;
679         mwindow->session->menueffect_h = h;
680         mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
681
682         if(plugin_list)
683         {
684                 list_title->reposition_window(mwindow->theme->menueffect_list_x,
685                         mwindow->theme->menueffect_list_y);
686                 list->reposition_window(mwindow->theme->menueffect_list_x,
687                         mwindow->theme->menueffect_list_y + list_title->get_h() + 5,
688                         mwindow->theme->menueffect_list_w,
689                         mwindow->theme->menueffect_list_h - list_title->get_h() - 5);
690         }
691
692         if(file_title) file_title->reposition_window(mwindow->theme->menueffect_file_x,
693                 mwindow->theme->menueffect_file_y);
694         int x = mwindow->theme->menueffect_tools_x;
695         int y = mwindow->theme->menueffect_tools_y;
696         if(format_tools) format_tools->reposition_window(x, y);
697         if(loadmode) loadmode->reposition_window(x, y);
698         return 0;
699 }
700
701
702
703 MenuEffectWindowOK::MenuEffectWindowOK(MenuEffectWindow *window)
704  : BC_OKButton(window)
705 {
706         this->window = window;
707 }
708
709 int MenuEffectWindowOK::handle_event()
710 {
711         if(window->plugin_list)
712                 window->result = window->list->get_selection_number(0, 0);
713
714         window->set_done(0);
715         return 1;
716 }
717
718 int MenuEffectWindowOK::keypress_event()
719 {
720         if(get_keypress() == RETURN)
721         {
722                 handle_event();
723                 return 1;
724         }
725         return 0;
726 }
727
728 MenuEffectWindowCancel::MenuEffectWindowCancel(MenuEffectWindow *window)
729  : BC_CancelButton(window)
730 {
731         this->window = window;
732 }
733
734 int MenuEffectWindowCancel::handle_event()
735 {
736         window->set_done(1);
737         return 1;
738 }
739
740 int MenuEffectWindowCancel::keypress_event()
741 {
742         if(get_keypress() == ESC)
743         {
744                 handle_event();
745                 return 1;
746         }
747         return 0;
748 }
749
750 MenuEffectWindowList::MenuEffectWindowList(MenuEffectWindow *window,
751         int x,
752         int y,
753         int w,
754         int h,
755         ArrayList<BC_ListBoxItem*> *plugin_list)
756  : BC_ListBox(x,
757                 y,
758                 w,
759                 h,
760                 LISTBOX_TEXT,
761                 plugin_list)
762 {
763         this->window = window;
764 }
765
766 int MenuEffectWindowList::handle_event()
767 {
768         window->result = get_selection_number(0, 0);
769         window->set_done(0);
770         return 1;
771 }
772
773 #define PROMPT_TEXT _("Set up effect panel and hit \"OK\"")
774
775 MenuEffectPrompt::MenuEffectPrompt(MWindow *mwindow)
776  : BC_Window(_(PROGRAM_NAME ": Effect Prompt"),
777                 mwindow->gui->get_abs_cursor_x(1) - 260 / 2,
778                 mwindow->gui->get_abs_cursor_y(1) - 300,
779                 MenuEffectPrompt::calculate_w(mwindow->gui),
780                 MenuEffectPrompt::calculate_h(mwindow->gui),
781                 MenuEffectPrompt::calculate_w(mwindow->gui),
782                 MenuEffectPrompt::calculate_h(mwindow->gui),
783                 0,
784                 0,
785                 1)
786 {
787 }
788
789 int MenuEffectPrompt::calculate_w(BC_WindowBase *gui)
790 {
791         int w = BC_Title::calculate_w(gui, PROMPT_TEXT) + 10;
792         w = MAX(w, BC_OKButton::calculate_w() + BC_CancelButton::calculate_w() + 30);
793         return w;
794 }
795
796 int MenuEffectPrompt::calculate_h(BC_WindowBase *gui)
797 {
798         int h = BC_Title::calculate_h(gui, PROMPT_TEXT);
799         h += BC_OKButton::calculate_h() + 30;
800         return h;
801 }
802
803
804 void MenuEffectPrompt::create_objects()
805 {
806         int x = 10, y = 10;
807         BC_Title *title;
808         add_subwindow(title = new BC_Title(x, y, PROMPT_TEXT));
809         add_subwindow(new BC_OKButton(this));
810         add_subwindow(new BC_CancelButton(this));
811         show_window();
812         raise_window();
813 }
814