r665: Merged the official release 2.0.
[cinelerra_cv.git] / cinelerra / menueffects.C
blob22d87830430cd8aa36c6e1b69fab83776eb161fd
1 #include "asset.h"
2 #include "clip.h"
3 #include "confirmsave.h"
4 #include "defaults.h"
5 #include "edl.h"
6 #include "edlsession.h"
7 #include "errorbox.h"
8 #include "file.h"
9 #include "formatcheck.h"
10 #include "indexfile.h"
11 #include "keyframe.h"
12 #include "keys.h"
13 #include "labels.h"
14 #include "language.h"
15 #include "loadmode.h"
16 #include "localsession.h"
17 #include "mainmenu.h"
18 #include "mainsession.h"
19 #include "mainundo.h"
20 #include "mwindow.h"
21 #include "mwindowgui.h"
22 #include "menueffects.h"
23 #include "playbackengine.h"
24 #include "pluginarray.h"
25 #include "pluginserver.h"
26 #include "preferences.h"
27 #include "render.h"
28 #include "sighandler.h"
29 #include "theme.h"
30 #include "tracks.h"
34 MenuEffects::MenuEffects(MWindow *mwindow)
35  : BC_MenuItem(_("Render effect..."))
37         this->mwindow = mwindow;
40 MenuEffects::~MenuEffects()
45 int MenuEffects::handle_event()
47         thread->set_title("");
48         thread->start();
55 MenuEffectPacket::MenuEffectPacket(char *path, int64_t start, int64_t end)
57         this->start = start;
58         this->end = end;
59         strcpy(this->path, path);
62 MenuEffectPacket::~MenuEffectPacket()
71 MenuEffectThread::MenuEffectThread(MWindow *mwindow)
73         this->mwindow = mwindow;
74         sprintf(title, "");
77 MenuEffectThread::~MenuEffectThread()
85 int MenuEffectThread::set_title(char *title)
87         strcpy(this->title, title);
90 // for recent effect menu items and running new effects
91 // prompts for an effect if title is blank
92 void MenuEffectThread::run()
94 // get stuff from main window
95         ArrayList<PluginServer*> *plugindb = mwindow->plugindb;
96         Defaults *defaults = mwindow->defaults;
97         ArrayList<BC_ListBoxItem*> plugin_list;
98         ArrayList<PluginServer*> local_plugindb;
99         char string[1024];
100         int i;
101         int result = 0;
102 // Default configuration
103         Asset default_asset;
104 // Output
105         ArrayList<Asset*> assets;
108 // check for recordable tracks
109         if(!get_recordable_tracks(&default_asset))
110         {
111                 sprintf(string, _("No recordable tracks specified."));
112                 ErrorBox error(PROGRAM_NAME ": Error");
113                 error.create_objects(string);
114                 error.run_window();
115                 return;
116         }
118 // check for plugins
119         if(!plugindb->total)
120         {
121                 sprintf(string, _("No plugins available."));
122                 ErrorBox error(PROGRAM_NAME ": Error");
123                 error.create_objects(string);
124                 error.run_window();
125                 return;
126         }
129 // get default attributes for output file
130 // used after completion
131         get_derived_attributes(&default_asset, defaults);
132 //      to_tracks = defaults->get("RENDER_EFFECT_TO_TRACKS", 1);
133         load_mode = defaults->get("RENDER_EFFECT_LOADMODE", LOAD_PASTE);
134         strategy = defaults->get("RENDER_EFFECT_STRATEGY", SINGLE_PASS);
136 // get plugin information
137         int need_plugin;
138         if(!strlen(title)) 
139                 need_plugin = 1; 
140         else 
141                 need_plugin = 0;
143 // generate a list of plugins for the window
144         if(need_plugin)
145         {
146                 mwindow->create_plugindb(default_asset.audio_data, 
147                         default_asset.video_data, 
148                         -1, 
149                         0,
150                         0,
151                         local_plugindb);
153                 for(int i = 0; i < local_plugindb.total; i++)
154                 {
155                         plugin_list.append(new BC_ListBoxItem(_(local_plugindb.values[i]->title)));
156                 }
157         }
159 // find out which effect to run and get output file
160         int plugin_number, format_error = 0;
162         do
163         {
164                 {
165                         MenuEffectWindow window(mwindow, 
166                                 this, 
167                                 need_plugin ? &plugin_list : 0, 
168                                 &default_asset);
169                         window.create_objects();
170                         result = window.run_window();
171                         plugin_number = window.result;
172                 }
174                 if(!result)
175                 {
176                         FormatCheck format_check(&default_asset);
177                         format_error = format_check.check_format();
178                 }
179         }while(format_error && !result);
181 // save defaults
182         save_derived_attributes(&default_asset, defaults);
183         defaults->update("RENDER_EFFECT_LOADMODE", load_mode);
184         defaults->update("RENDER_EFFECT_STRATEGY", strategy);
185         mwindow->save_defaults();
187 // get plugin server to use and delete the plugin list
188         PluginServer *plugin_server = 0;
189         PluginServer *plugin = 0;
190         if(need_plugin)
191         {
192                 plugin_list.remove_all_objects();
193                 if(plugin_number > -1)
194                 {
195                         plugin_server = local_plugindb.values[plugin_number];
196                         strcpy(title, plugin_server->title);
197                 }
198         }
199         else
200         {
201                 for(int i = 0; i < plugindb->total && !plugin_server; i++)
202                 {
203                         if(!strcmp(plugindb->values[i]->title, title))
204                         {
205                                 plugin_server = plugindb->values[i];
206                                 plugin_number = i;
207                         }
208                 }
209         }
211 // Update the  most recently used effects and copy the plugin server.
212         if(plugin_server)
213         {
214                 plugin = new PluginServer(*plugin_server);
215                 fix_menu(title);
216         }
218         if(!result && !strlen(default_asset.path))
219         {
220                 result = 1;        // no output path given
221                 ErrorBox error(PROGRAM_NAME ": Error");
222                 error.create_objects(_("No output file specified."));
223                 error.run_window();
224         }
226         if(!result && plugin_number < 0)
227         {
228                 result = 1;        // no output path given
229                 ErrorBox error(PROGRAM_NAME ": Error");
230                 error.create_objects(_("No effect selected."));
231                 error.run_window();
232         }
234 // Configuration for realtime plugins.
235         KeyFrame plugin_data;        
237 // get selection to render
238 // Range
239         double total_start, total_end;
241         total_start = mwindow->edl->local_session->get_selectionstart();
244         if(mwindow->edl->local_session->get_selectionend() == 
245                 mwindow->edl->local_session->get_selectionstart())
246                 total_end = mwindow->edl->tracks->total_playable_length();
247         else
248                 total_end = mwindow->edl->local_session->get_selectionend();
252 // get native units for range
253         total_start = to_units(total_start, 0);
254         total_end = to_units(total_end, 1);
258 // Trick boundaries in case of a non-realtime synthesis plugin
259         if(plugin && 
260                 !plugin->realtime && 
261                 total_end == total_start) total_end = total_start + 1;
263 // Units are now in the track's units.
264         int64_t total_length = (int64_t)total_end - (int64_t)total_start;
265 // length of output file
266         int64_t output_start, output_end;        
268         if(!result && total_length <= 0)
269         {
270                 result = 1;        // no output path given
271                 ErrorBox error(PROGRAM_NAME ": Error");
272                 error.create_objects(_("No selected range to process."));
273                 error.run_window();
274         }
276 // ========================= get keyframe from user
277         if(!result)
278         {
279 // ========================= realtime plugin 
280 // no get_parameters
281                 if(plugin->realtime)
282                 {
283 // Open a prompt GUI
284                         MenuEffectPrompt prompt(mwindow);
285                         prompt.create_objects();
286                         char title[BCTEXTLEN];
287                         sprintf(title, PROGRAM_NAME ": %s", plugin->title);
289 // Open the plugin GUI
290                         plugin->set_mwindow(mwindow);
291                         plugin->set_keyframe(&plugin_data);
292                         plugin->set_prompt(&prompt);
293                         plugin->open_plugin(0, mwindow->preferences, mwindow->edl, 0, -1);
294 // Must set parameters since there is no plugin object to draw from.
295                         plugin->get_parameters((int64_t)total_start,
296                                 (int64_t)total_end,
297                                 1);
298                         plugin->show_gui();
300 // wait for user input
301                         result = prompt.run_window();
303 // Close plugin.
304                         plugin->save_data(&plugin_data);
305                         delete plugin;
306                         default_asset.sample_rate = mwindow->edl->session->sample_rate;
307                         default_asset.frame_rate = mwindow->edl->session->frame_rate;
308                         realtime = 1;
309                 }
310                 else
311 // ============================non realtime plugin 
312                 {
313                         plugin->set_mwindow(mwindow);
314                         plugin->open_plugin(0, mwindow->preferences, mwindow->edl, 0, -1);
315                         result = plugin->get_parameters((int64_t)total_start, 
316                                 (int64_t)total_end, 
317                                 get_recordable_tracks(&default_asset));
318 // some plugins can change the sample rate and the frame rate
321                         if(!result)
322                         {
323                                 default_asset.sample_rate = plugin->get_samplerate();
324                                 default_asset.frame_rate = plugin->get_framerate();
325                         }
326                         delete plugin;
327                         realtime = 0;
328                 }
330 // Should take from first recordable track
331                 default_asset.width = mwindow->edl->session->output_w;
332                 default_asset.height = mwindow->edl->session->output_h;
333         }
335 // Process the total length in fragments
336         ArrayList<MenuEffectPacket*> packets;
337         if(!result)
338         {
339                 Label *current_label = mwindow->edl->labels->first;
340                 mwindow->stop_brender();
342                 int current_number;
343                 int number_start;
344                 int total_digits;
345                 Render::get_starting_number(default_asset.path, 
346                         current_number,
347                         number_start, 
348                         total_digits);
352 // Construct all packets for single overwrite confirmation
353                 for(int64_t fragment_start = (int64_t)total_start, fragment_end;
354                         fragment_start < (int64_t)total_end;
355                         fragment_start = fragment_end)
356                 {
357 // Get fragment end
358                         if(strategy == FILE_PER_LABEL || strategy == FILE_PER_LABEL_FARM)
359                         {
360                                 while(current_label  &&
361                                         to_units(current_label->position, 0) <= fragment_start)
362                                         current_label = current_label->next;
363                                 if(!current_label)
364                                         fragment_end = (int64_t)total_end;
365                                 else
366                                         fragment_end = to_units(current_label->position, 0);
367                         }
368                         else
369                         {
370                                 fragment_end = (int64_t)total_end;
371                         }
373 // Get path
374                         char path[BCTEXTLEN];
375                         if(strategy == FILE_PER_LABEL || strategy == FILE_PER_LABEL_FARM) 
376                                 Render::create_filename(path, 
377                                         default_asset.path, 
378                                         current_number,
379                                         total_digits,
380                                         number_start);
381                         else
382                                 strcpy(path, default_asset.path);
383                         current_number++;
385                         MenuEffectPacket *packet = new MenuEffectPacket(path, 
386                                 fragment_start,
387                                 fragment_end);
388                         packets.append(packet);
389                 }
392 // Test existence of files
393                 ArrayList<char*> paths;
394                 for(int i = 0; i < packets.total; i++)
395                 {
396                         paths.append(packets.values[i]->path);
397                 }
398                 result = ConfirmSave::test_files(mwindow, &paths);
399                 paths.remove_all();
400         }
404         for(int current_packet = 0; 
405                 current_packet < packets.total && !result; 
406                 current_packet++)
407         {
408                 Asset *asset = new Asset(default_asset);
409                 MenuEffectPacket *packet = packets.values[current_packet];
410                 int64_t fragment_start = packet->start;
411                 int64_t fragment_end = packet->end;
412                 strcpy(asset->path, packet->path);
414                 assets.append(asset);
415                 File *file = new File;
417 // Open the output file after getting the information because the sample rate
418 // is needed here.
419                 if(!result)
420                 {
421 // open output file in write mode
422                         file->set_processors(mwindow->preferences->processors);
423                         if(file->open_file(mwindow->preferences, 
424                                 asset, 
425                                 0, 
426                                 1, 
427                                 mwindow->edl->session->sample_rate, 
428                                 mwindow->edl->session->frame_rate))
429                         {
430 // open failed
431                                 sprintf(string, _("Couldn't open %s"), asset->path);
432                                 ErrorBox error(PROGRAM_NAME ": Error");
433                                 error.create_objects(string);
434                                 error.run_window();
435                                 result = 1;
436                         }
437                         else
438                         {
439                                 mwindow->sighandler->push_file(file);
440                                 IndexFile::delete_index(mwindow->preferences, asset);
441                         }
442                 }
444 // run plugins
445                 if(!result)
446                 {
447 // position file
448                         output_start = 0;
450                         PluginArray *plugin_array;
451                         plugin_array = create_plugin_array();
453                         plugin_array->start_plugins(mwindow, 
454                                 mwindow->edl, 
455                                 plugin_server, 
456                                 &plugin_data,
457                                 fragment_start,
458                                 fragment_end,
459                                 file);
460                         plugin_array->run_plugins();
462                         plugin_array->stop_plugins();
463                         mwindow->sighandler->pull_file(file);
464                         file->close_file();
465                         asset->audio_length = file->asset->audio_length;
466                         asset->video_length = file->asset->video_length;
467                         delete plugin_array;
468                 }
470                 delete file;
471         }
473         packets.remove_all_objects();
475 // paste output to tracks
476         if(!result && load_mode != LOAD_NOTHING)
477         {
478                 mwindow->gui->lock_window("MenuEffectThread::run");
480                 if(load_mode == LOAD_PASTE)
481                         mwindow->clear(0);
482                 mwindow->load_assets(&assets,
483                         -1,
484                         load_mode,
485                         0,
486                         0,
487                         mwindow->edl->session->labels_follow_edits, 
488                         mwindow->edl->session->plugins_follow_edits);
491                 mwindow->save_backup();
492                 mwindow->undo->update_undo(title, LOAD_ALL);
496                 mwindow->restart_brender();
497                 mwindow->update_plugin_guis();
498                 mwindow->gui->update(1, 
499                         2,
500                         1,
501                         1,
502                         1,
503                         1,
504                         0);
505                 mwindow->sync_parameters(CHANGE_ALL);
506                 mwindow->gui->unlock_window();
507         }
509         assets.remove_all_objects();
515 MenuEffectItem::MenuEffectItem(MenuEffects *menueffect, char *string)
516  : BC_MenuItem(string)
518         this->menueffect = menueffect; 
520 int MenuEffectItem::handle_event()
522         menueffect->thread->set_title(get_text());
523         menueffect->thread->start();
537 MenuEffectWindow::MenuEffectWindow(MWindow *mwindow, 
538         MenuEffectThread *menueffects, 
539         ArrayList<BC_ListBoxItem*> *plugin_list, 
540         Asset *asset)
541  : BC_Window(PROGRAM_NAME ": Render effect", 
542                 mwindow->gui->get_abs_cursor_x(1),
543                 mwindow->gui->get_abs_cursor_y(1) - mwindow->session->menueffect_h / 2,
544                 mwindow->session->menueffect_w, 
545                 mwindow->session->menueffect_h, 
546                 580,
547                 350,
548                 1,
549                 0,
550                 1)
552         this->menueffects = menueffects; 
553         this->plugin_list = plugin_list; 
554         this->asset = asset;
555         this->mwindow = mwindow;
558 MenuEffectWindow::~MenuEffectWindow()
560         delete format_tools;
565 int MenuEffectWindow::create_objects()
567         int x, y;
568         result = -1;
569         mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
571 // only add the list if needed
572         if(plugin_list)
573         {
574                 add_subwindow(list_title = new BC_Title(mwindow->theme->menueffect_list_x, 
575                         mwindow->theme->menueffect_list_y, 
576                         _("Select an effect")));
577                 add_subwindow(list = new MenuEffectWindowList(this, 
578                         mwindow->theme->menueffect_list_x, 
579                         mwindow->theme->menueffect_list_y + list_title->get_h() + 5, 
580                         mwindow->theme->menueffect_list_w,
581                         mwindow->theme->menueffect_list_h - list_title->get_h() - 5,
582                         plugin_list));
583         }
585         add_subwindow(file_title = new BC_Title(mwindow->theme->menueffect_file_x, 
586                 mwindow->theme->menueffect_file_y, 
587                 (char*)((menueffects->strategy == FILE_PER_LABEL  || menueffects->strategy == FILE_PER_LABEL_FARM) ? 
588                         _("Select the first file to render to:") : 
589                         _("Select a file to render to:"))));
591         x = mwindow->theme->menueffect_tools_x;
592         y = mwindow->theme->menueffect_tools_y;
593         format_tools = new FormatTools(mwindow,
594                                         this, 
595                                         asset);
596         format_tools->create_objects(x, 
597                                         y, 
598                                         asset->audio_data, 
599                                         asset->video_data, 
600                                         0, 
601                                         0, 
602                                         0,
603                                         1,
604                                         0,
605                                         0,
606                                         &menueffects->strategy,
607                                         0);
609         loadmode = new LoadMode(mwindow, 
610                 this, 
611                 x, 
612                 y, 
613                 &menueffects->load_mode, 
614                 1);
615         loadmode->create_objects();
617         add_subwindow(new MenuEffectWindowOK(this));
618         add_subwindow(new MenuEffectWindowCancel(this));
619         show_window();
620         flush();
621         return 0;
624 int MenuEffectWindow::resize_event(int w, int h)
626         mwindow->session->menueffect_w = w;
627         mwindow->session->menueffect_h = h;
628         mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
630         if(plugin_list)
631         {
632                 list_title->reposition_window(mwindow->theme->menueffect_list_x, 
633                         mwindow->theme->menueffect_list_y);
634                 list->reposition_window(mwindow->theme->menueffect_list_x, 
635                         mwindow->theme->menueffect_list_y + list_title->get_h() + 5, 
636                         mwindow->theme->menueffect_list_w,
637                         mwindow->theme->menueffect_list_h - list_title->get_h() - 5);
638         }
640         file_title->reposition_window(mwindow->theme->menueffect_file_x, 
641                 mwindow->theme->menueffect_file_y);
642         int x = mwindow->theme->menueffect_tools_x;
643         int y = mwindow->theme->menueffect_tools_y;
644         format_tools->reposition_window(x, y);
645         loadmode->reposition_window(x, y);
650 MenuEffectWindowOK::MenuEffectWindowOK(MenuEffectWindow *window)
651  : BC_OKButton(window)
653         this->window = window; 
656 int MenuEffectWindowOK::handle_event() 
658         if(window->plugin_list) 
659                 window->result = window->list->get_selection_number(0, 0); 
660         
661         window->set_done(0); 
664 int MenuEffectWindowOK::keypress_event() 
666         if(get_keypress() == RETURN) 
667         { 
668                 handle_event(); 
669                 return 1; 
670         }
671         return 0;
674 MenuEffectWindowCancel::MenuEffectWindowCancel(MenuEffectWindow *window)
675  : BC_CancelButton(window)
677         this->window = window; 
680 int MenuEffectWindowCancel::handle_event() 
682         window->set_done(1); 
685 int MenuEffectWindowCancel::keypress_event() 
687         if(get_keypress() == ESC) 
688         { 
689                 handle_event(); 
690                 return 1; 
691         }
692         return 0;
695 MenuEffectWindowList::MenuEffectWindowList(MenuEffectWindow *window, 
696         int x, 
697         int y, 
698         int w, 
699         int h, 
700         ArrayList<BC_ListBoxItem*> *plugin_list)
701  : BC_ListBox(x, 
702                 y, 
703                 w, 
704                 h, 
705                 LISTBOX_TEXT, 
706                 plugin_list)
708         this->window = window; 
711 int MenuEffectWindowList::handle_event() 
713         window->result = get_selection_number(0, 0);
714         window->set_done(0); 
717 #define PROMPT_TEXT _("Set up effect panel and hit \"OK\"")
719 MenuEffectPrompt::MenuEffectPrompt(MWindow *mwindow)
720  : BC_Window(PROGRAM_NAME ": Effect Prompt", 
721                 mwindow->gui->get_abs_cursor_x(1) - 260 / 2,
722                 mwindow->gui->get_abs_cursor_y(1) - 300,
723                 MenuEffectPrompt::calculate_w(mwindow->gui), 
724                 MenuEffectPrompt::calculate_h(mwindow->gui), 
725                 MenuEffectPrompt::calculate_w(mwindow->gui),
726                 MenuEffectPrompt::calculate_h(mwindow->gui),
727                 0,
728                 0,
729                 1)
733 int MenuEffectPrompt::calculate_w(BC_WindowBase *gui)
735         int w = BC_Title::calculate_w(gui, PROMPT_TEXT) + 10;
736         w = MAX(w, BC_OKButton::calculate_w() + BC_CancelButton::calculate_w() + 30);
737         return w;
740 int MenuEffectPrompt::calculate_h(BC_WindowBase *gui)
742         int h = BC_Title::calculate_h(gui, PROMPT_TEXT);
743         h += BC_OKButton::calculate_h() + 30;
744         return h;
748 int MenuEffectPrompt::create_objects()
750         int x = 10, y = 10;
751         BC_Title *title;
752         add_subwindow(title = new BC_Title(x, y, PROMPT_TEXT));
753         add_subwindow(new BC_OKButton(this));
754         add_subwindow(new BC_CancelButton(this));
755         show_window();
756         raise_window();
757         flush();
758         return 0;