mixer
[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_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, 1);
520
521                 mwindow->load_assets(&assets, -1, load_mode, 0, 0,
522                         mwindow->edl->session->labels_follow_edits,
523                         mwindow->edl->session->plugins_follow_edits,
524                         mwindow->edl->session->autos_follow_edits,
525                         0); // overwrite
526
527                 mwindow->save_backup();
528                 mwindow->undo->update_undo_after(title, LOAD_ALL);
529
530                 mwindow->restart_brender();
531                 mwindow->update_plugin_guis();
532                 mwindow->gui->update(1, 2, 1, 1, 1, 1, 0);
533                 mwindow->sync_parameters(CHANGE_ALL);
534                 mwindow->gui->unlock_window();
535
536                 mwindow->awindow->gui->async_update_assets();
537         }
538
539         for(int i = 0; i < assets.total; i++)
540                 assets.values[i]->Garbage::remove_user();
541         assets.remove_all();
542
543         default_asset->Garbage::remove_user();
544 }
545
546
547
548
549
550
551
552 MenuEffectItem::MenuEffectItem(MenuEffects *menueffect, const char *string)
553  : BC_MenuItem(string)
554 {
555         this->menueffect = menueffect;
556 }
557 int MenuEffectItem::handle_event()
558 {
559         menueffect->thread->set_title(get_text());
560         menueffect->thread->start();
561         return 1;
562 }
563
564
565
566
567
568
569
570
571
572
573
574
575 MenuEffectWindow::MenuEffectWindow(MWindow *mwindow,
576         MenuEffectThread *menueffects,
577         ArrayList<BC_ListBoxItem*> *plugin_list,
578         Asset *asset)
579  : BC_Window(_(PROGRAM_NAME ": Render effect"),
580                 mwindow->gui->get_abs_cursor_x(1),
581                 mwindow->gui->get_abs_cursor_y(1) - mwindow->session->menueffect_h / 2,
582                 mwindow->session->menueffect_w,
583                 mwindow->session->menueffect_h,
584                 580,
585                 350,
586                 1,
587                 0,
588                 1)
589 {
590         this->menueffects = menueffects;
591         this->plugin_list = plugin_list;
592         this->asset = asset;
593         this->mwindow = mwindow;
594         file_title = 0;
595         format_tools = 0;
596         loadmode = 0;
597 }
598
599 MenuEffectWindow::~MenuEffectWindow()
600 {
601         lock_window("MenuEffectWindow::~MenuEffectWindow");
602         delete format_tools;
603         unlock_window();
604 }
605
606
607
608 void MenuEffectWindow::create_objects()
609 {
610         int x, y;
611         result = -1;
612         mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
613
614         lock_window("MenuEffectWindow::create_objects");
615 // only add the list if needed
616         if(plugin_list)
617         {
618                 add_subwindow(list_title = new BC_Title(mwindow->theme->menueffect_list_x,
619                         mwindow->theme->menueffect_list_y,
620                         _("Select an effect")));
621                 add_subwindow(list = new MenuEffectWindowList(this,
622                         mwindow->theme->menueffect_list_x,
623                         mwindow->theme->menueffect_list_y + list_title->get_h() + 5,
624                         mwindow->theme->menueffect_list_w,
625                         mwindow->theme->menueffect_list_h - list_title->get_h() - 5,
626                         plugin_list));
627         }
628
629         add_subwindow(file_title = new BC_Title(
630                 mwindow->theme->menueffect_file_x,
631                 mwindow->theme->menueffect_file_y,
632                 (char*)((menueffects->strategy == FILE_PER_LABEL  || menueffects->strategy == FILE_PER_LABEL_FARM) ?
633                         _("Select the first file to render to:") :
634                         _("Select a file to render to:"))));
635
636         x = mwindow->theme->menueffect_tools_x;
637         y = mwindow->theme->menueffect_tools_y;
638         format_tools = new FormatTools(mwindow,
639                                         this,
640                                         asset);
641         format_tools->create_objects(x,
642                                         y,
643                                         asset->audio_data,
644                                         asset->video_data,
645                                         0,
646                                         0,
647                                         0,
648                                         1,
649                                         0,
650                                         0,
651                                         &menueffects->strategy,
652                                         0);
653
654         loadmode = new LoadMode(mwindow, this, x, y, &menueffects->load_mode, 1);
655         loadmode->create_objects();
656
657         add_subwindow(new MenuEffectWindowOK(this));
658         add_subwindow(new MenuEffectWindowCancel(this));
659         show_window();
660         unlock_window();
661 }
662
663 int MenuEffectWindow::resize_event(int w, int h)
664 {
665         mwindow->session->menueffect_w = w;
666         mwindow->session->menueffect_h = h;
667         mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
668
669         if(plugin_list)
670         {
671                 list_title->reposition_window(mwindow->theme->menueffect_list_x,
672                         mwindow->theme->menueffect_list_y);
673                 list->reposition_window(mwindow->theme->menueffect_list_x,
674                         mwindow->theme->menueffect_list_y + list_title->get_h() + 5,
675                         mwindow->theme->menueffect_list_w,
676                         mwindow->theme->menueffect_list_h - list_title->get_h() - 5);
677         }
678
679         if(file_title) file_title->reposition_window(mwindow->theme->menueffect_file_x,
680                 mwindow->theme->menueffect_file_y);
681         int x = mwindow->theme->menueffect_tools_x;
682         int y = mwindow->theme->menueffect_tools_y;
683         if(format_tools) format_tools->reposition_window(x, y);
684         if(loadmode) loadmode->reposition_window(x, y);
685         return 0;
686 }
687
688
689
690 MenuEffectWindowOK::MenuEffectWindowOK(MenuEffectWindow *window)
691  : BC_OKButton(window)
692 {
693         this->window = window;
694 }
695
696 int MenuEffectWindowOK::handle_event()
697 {
698         if(window->plugin_list)
699                 window->result = window->list->get_selection_number(0, 0);
700
701         window->set_done(0);
702         return 1;
703 }
704
705 int MenuEffectWindowOK::keypress_event()
706 {
707         if(get_keypress() == RETURN)
708         {
709                 handle_event();
710                 return 1;
711         }
712         return 0;
713 }
714
715 MenuEffectWindowCancel::MenuEffectWindowCancel(MenuEffectWindow *window)
716  : BC_CancelButton(window)
717 {
718         this->window = window;
719 }
720
721 int MenuEffectWindowCancel::handle_event()
722 {
723         window->set_done(1);
724         return 1;
725 }
726
727 int MenuEffectWindowCancel::keypress_event()
728 {
729         if(get_keypress() == ESC)
730         {
731                 handle_event();
732                 return 1;
733         }
734         return 0;
735 }
736
737 MenuEffectWindowList::MenuEffectWindowList(MenuEffectWindow *window,
738         int x,
739         int y,
740         int w,
741         int h,
742         ArrayList<BC_ListBoxItem*> *plugin_list)
743  : BC_ListBox(x,
744                 y,
745                 w,
746                 h,
747                 LISTBOX_TEXT,
748                 plugin_list)
749 {
750         this->window = window;
751 }
752
753 int MenuEffectWindowList::handle_event()
754 {
755         window->result = get_selection_number(0, 0);
756         window->set_done(0);
757         return 1;
758 }
759
760 #define PROMPT_TEXT _("Set up effect panel and hit \"OK\"")
761
762 MenuEffectPrompt::MenuEffectPrompt(MWindow *mwindow)
763  : BC_Window(_(PROGRAM_NAME ": Effect Prompt"),
764                 mwindow->gui->get_abs_cursor_x(1) - 260 / 2,
765                 mwindow->gui->get_abs_cursor_y(1) - 300,
766                 MenuEffectPrompt::calculate_w(mwindow->gui),
767                 MenuEffectPrompt::calculate_h(mwindow->gui),
768                 MenuEffectPrompt::calculate_w(mwindow->gui),
769                 MenuEffectPrompt::calculate_h(mwindow->gui),
770                 0,
771                 0,
772                 1)
773 {
774 }
775
776 int MenuEffectPrompt::calculate_w(BC_WindowBase *gui)
777 {
778         int w = BC_Title::calculate_w(gui, PROMPT_TEXT) + 10;
779         w = MAX(w, BC_OKButton::calculate_w() + BC_CancelButton::calculate_w() + 30);
780         return w;
781 }
782
783 int MenuEffectPrompt::calculate_h(BC_WindowBase *gui)
784 {
785         int h = BC_Title::calculate_h(gui, PROMPT_TEXT);
786         h += BC_OKButton::calculate_h() + 30;
787         return h;
788 }
789
790
791 void MenuEffectPrompt::create_objects()
792 {
793         int x = 10, y = 10;
794         BC_Title *title;
795         add_subwindow(title = new BC_Title(x, y, PROMPT_TEXT));
796         add_subwindow(new BC_OKButton(this));
797         add_subwindow(new BC_CancelButton(this));
798         show_window();
799         raise_window();
800 }
801