4 * Copyright (C) 2010 Adam Williams <broadcast at earthling dot net>
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.
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.
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
24 #include "awindowgui.h"
26 #include "confirmsave.h"
29 #include "edlsession.h"
32 #include "formatcheck.h"
33 #include "indexfile.h"
39 #include "localsession.h"
41 #include "mainsession.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"
51 #include "sighandler.h"
57 MenuEffects::MenuEffects(MWindow *mwindow)
58 : BC_MenuItem(_("Render effect..."))
60 this->mwindow = mwindow;
63 MenuEffects::~MenuEffects()
68 int MenuEffects::handle_event()
70 thread->set_title("");
79 MenuEffectPacket::MenuEffectPacket(char *path, int64_t start, int64_t end)
83 strcpy(this->path, path);
86 MenuEffectPacket::~MenuEffectPacket()
95 MenuEffectThread::MenuEffectThread(MWindow *mwindow, MenuEffects *menu_item)
97 this->mwindow = mwindow;
98 this->menu_item = menu_item;
100 dead_plugins = new ArrayList<PluginServer*>;
103 MenuEffectThread::~MenuEffectThread()
112 int MenuEffectThread::set_title(const char *title)
114 strcpy(this->title, title);
118 // for recent effect menu items and running new effects
119 // prompts for an effect if title is blank
120 void MenuEffectThread::run()
122 for(int i = 0; i < dead_plugins->size(); i++)
124 delete dead_plugins->get(i);
126 dead_plugins->remove_all();
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;
138 // Default configuration
139 Asset *default_asset = new Asset;
141 ArrayList<Indexable*> assets;
144 // check for recordable tracks
145 if(!get_recordable_tracks(default_asset))
147 sprintf(string, _("No recordable tracks specified."));
148 ErrorBox error(PROGRAM_NAME ": Error");
149 error.create_objects(string);
151 default_asset->Garbage::remove_user();
158 sprintf(string, _("No plugins available."));
159 ErrorBox error(PROGRAM_NAME ": Error");
160 error.create_objects(string);
162 default_asset->Garbage::remove_user();
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);
174 // get plugin information
181 // generate a list of plugins for the window
184 mwindow->search_plugindb(default_asset->audio_data,
185 default_asset->video_data,
191 for(int i = 0; i < local_plugindb.total; i++)
193 plugin_list.append(new BC_ListBoxItem(_(local_plugindb.values[i]->title)));
197 // find out which effect to run and get output file
198 int plugin_number, format_error = 0;
203 MenuEffectWindow window(mwindow,
205 need_plugin ? &plugin_list : 0,
207 window.create_objects();
208 result = window.run_window();
209 plugin_number = window.result;
214 FormatCheck format_check(default_asset);
215 format_error = format_check.check_format();
217 }while(format_error && !result);
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();
225 // get plugin server to use and delete the plugin list
226 PluginServer *plugin_server = 0;
227 PluginServer *plugin = 0;
230 plugin_list.remove_all_objects();
231 if(plugin_number > -1)
233 plugin_server = local_plugindb.values[plugin_number];
234 strcpy(title, plugin_server->title);
239 for(int i = 0; i < plugindb->total && !plugin_server; i++)
241 if(!strcmp(plugindb->values[i]->title, title))
243 plugin_server = plugindb->values[i];
249 // Update the most recently used effects and copy the plugin server.
252 plugin = new PluginServer(*plugin_server);
256 if(!result && !strlen(default_asset->path))
258 result = 1; // no output path given
259 ErrorBox error(PROGRAM_NAME ": Error");
260 error.create_objects(_("No output file specified."));
264 if(!result && plugin_number < 0)
266 result = 1; // no output path given
267 ErrorBox error(PROGRAM_NAME ": Error");
268 error.create_objects(_("No effect selected."));
272 // Configuration for realtime plugins.
273 KeyFrame plugin_data;
275 // get selection to render
277 double total_start, total_end;
279 total_start = mwindow->edl->local_session->get_selectionstart();
282 if(mwindow->edl->local_session->get_selectionend() ==
283 mwindow->edl->local_session->get_selectionstart())
284 total_end = mwindow->edl->tracks->total_playable_length();
286 total_end = mwindow->edl->local_session->get_selectionend();
290 // get native units for range
291 total_start = to_units(total_start, 0);
292 total_end = to_units(total_end, 1);
296 // Trick boundaries in case of a non-realtime synthesis plugin
299 total_end == total_start) total_end = total_start + 1;
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
305 if(!result && total_length <= 0)
307 result = 1; // no output path given
308 ErrorBox error(PROGRAM_NAME ": Error");
309 error.create_objects(_("No selected range to process."));
313 // ========================= get keyframe from user
316 // ========================= realtime plugin
321 MenuEffectPrompt prompt(mwindow);
322 prompt.create_objects();
323 char title[BCTEXTLEN];
324 sprintf(title, PROGRAM_NAME ": %s", plugin->title);
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,
337 // wait for user input
338 result = prompt.run_window();
341 plugin->save_data(&plugin_data);
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;
351 // ============================non realtime plugin
353 plugin->set_mwindow(mwindow);
354 plugin->open_plugin(0, mwindow->preferences, mwindow->edl, 0);
355 result = plugin->get_parameters((int64_t)total_start,
357 get_recordable_tracks(default_asset));
358 // some plugins can change the sample rate and the frame rate
363 default_asset->sample_rate = plugin->get_samplerate();
364 default_asset->frame_rate = plugin->get_framerate();
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;
375 // Process the total length in fragments
376 ArrayList<MenuEffectPacket*> packets;
379 Label *current_label = mwindow->edl->labels->first;
380 mwindow->stop_brender();
385 Render::get_starting_number(default_asset->path,
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)
398 if(strategy == FILE_PER_LABEL || strategy == FILE_PER_LABEL_FARM)
400 while(current_label &&
401 to_units(current_label->position, 0) <= fragment_start)
402 current_label = current_label->next;
404 fragment_end = (int64_t)total_end;
406 fragment_end = to_units(current_label->position, 0);
410 fragment_end = (int64_t)total_end;
414 char path[BCTEXTLEN];
415 if(strategy == FILE_PER_LABEL || strategy == FILE_PER_LABEL_FARM)
416 Render::create_filename(path,
422 strcpy(path, default_asset->path);
425 MenuEffectPacket *packet = new MenuEffectPacket(path,
428 packets.append(packet);
432 // Test existence of files
433 ArrayList<char*> paths;
434 for(int i = 0; i < packets.total; i++)
436 paths.append(packets.values[i]->path);
438 result = ConfirmSave::test_files(mwindow, &paths);
444 for(int current_packet = 0;
445 current_packet < packets.total && !result;
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);
454 assets.append(asset);
455 File *file = new File;
457 // Open the output file after getting the information because the sample rate
461 // open output file in write mode
462 file->set_processors(mwindow->preferences->processors);
463 if(file->open_file(mwindow->preferences,
469 sprintf(string, _("Couldn't open %s"), asset->path);
470 ErrorBox error(PROGRAM_NAME ": Error");
471 error.create_objects(string);
477 mwindow->sighandler->push_file(file);
478 IndexFile::delete_index(mwindow->preferences,
487 PluginArray *plugin_array;
488 plugin_array = create_plugin_array();
490 plugin_array->start_plugins(mwindow,
497 plugin_array->run_plugins();
499 plugin_array->stop_plugins();
500 mwindow->sighandler->pull_file(file);
502 asset->audio_length = file->asset->audio_length;
503 asset->video_length = file->asset->video_length;
510 packets.remove_all_objects();
512 // paste output to tracks
513 if(!result && load_mode != LOADMODE_NOTHING)
515 mwindow->gui->lock_window("MenuEffectThread::run");
517 mwindow->undo->update_undo_before("", 0);
518 if(load_mode == LOADMODE_PASTE)
522 mwindow->load_assets(&assets,
527 mwindow->edl->session->labels_follow_edits,
528 mwindow->edl->session->plugins_follow_edits,
529 mwindow->edl->session->autos_follow_edits);
532 mwindow->save_backup();
533 mwindow->undo->update_undo_after(title, LOAD_ALL);
537 mwindow->restart_brender();
538 mwindow->update_plugin_guis();
539 mwindow->gui->update(1,
546 mwindow->sync_parameters(CHANGE_ALL);
547 mwindow->gui->unlock_window();
550 mwindow->awindow->gui->lock_window("MenuEffectThread::run");
551 mwindow->awindow->gui->update_assets();
552 mwindow->awindow->gui->flush();
553 mwindow->awindow->gui->unlock_window();
558 for(int i = 0; i < assets.total; i++)
559 assets.values[i]->Garbage::remove_user();
562 default_asset->Garbage::remove_user();
571 MenuEffectItem::MenuEffectItem(MenuEffects *menueffect, char *string)
572 : BC_MenuItem(string)
574 this->menueffect = menueffect;
576 int MenuEffectItem::handle_event()
578 menueffect->thread->set_title(get_text());
579 menueffect->thread->start();
594 MenuEffectWindow::MenuEffectWindow(MWindow *mwindow,
595 MenuEffectThread *menueffects,
596 ArrayList<BC_ListBoxItem*> *plugin_list,
598 : BC_Window(PROGRAM_NAME ": Render effect",
599 mwindow->gui->get_abs_cursor_x(1),
600 mwindow->gui->get_abs_cursor_y(1) - mwindow->session->menueffect_h / 2,
601 mwindow->session->menueffect_w,
602 mwindow->session->menueffect_h,
609 this->menueffects = menueffects;
610 this->plugin_list = plugin_list;
612 this->mwindow = mwindow;
618 MenuEffectWindow::~MenuEffectWindow()
620 lock_window("MenuEffectWindow::~MenuEffectWindow");
627 void MenuEffectWindow::create_objects()
631 mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
633 lock_window("MenuEffectWindow::create_objects");
634 // only add the list if needed
637 add_subwindow(list_title = new BC_Title(mwindow->theme->menueffect_list_x,
638 mwindow->theme->menueffect_list_y,
639 _("Select an effect")));
640 add_subwindow(list = new MenuEffectWindowList(this,
641 mwindow->theme->menueffect_list_x,
642 mwindow->theme->menueffect_list_y + list_title->get_h() + 5,
643 mwindow->theme->menueffect_list_w,
644 mwindow->theme->menueffect_list_h - list_title->get_h() - 5,
648 add_subwindow(file_title = new BC_Title(
649 mwindow->theme->menueffect_file_x,
650 mwindow->theme->menueffect_file_y,
651 (char*)((menueffects->strategy == FILE_PER_LABEL || menueffects->strategy == FILE_PER_LABEL_FARM) ?
652 _("Select the first file to render to:") :
653 _("Select a file to render to:"))));
655 x = mwindow->theme->menueffect_tools_x;
656 y = mwindow->theme->menueffect_tools_y;
657 format_tools = new FormatTools(mwindow,
660 format_tools->create_objects(x,
670 &menueffects->strategy,
673 loadmode = new LoadMode(mwindow,
677 &menueffects->load_mode,
680 loadmode->create_objects();
682 add_subwindow(new MenuEffectWindowOK(this));
683 add_subwindow(new MenuEffectWindowCancel(this));
688 int MenuEffectWindow::resize_event(int w, int h)
690 mwindow->session->menueffect_w = w;
691 mwindow->session->menueffect_h = h;
692 mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
696 list_title->reposition_window(mwindow->theme->menueffect_list_x,
697 mwindow->theme->menueffect_list_y);
698 list->reposition_window(mwindow->theme->menueffect_list_x,
699 mwindow->theme->menueffect_list_y + list_title->get_h() + 5,
700 mwindow->theme->menueffect_list_w,
701 mwindow->theme->menueffect_list_h - list_title->get_h() - 5);
704 if(file_title) file_title->reposition_window(mwindow->theme->menueffect_file_x,
705 mwindow->theme->menueffect_file_y);
706 int x = mwindow->theme->menueffect_tools_x;
707 int y = mwindow->theme->menueffect_tools_y;
708 if(format_tools) format_tools->reposition_window(x, y);
709 if(loadmode) loadmode->reposition_window(x, y);
715 MenuEffectWindowOK::MenuEffectWindowOK(MenuEffectWindow *window)
716 : BC_OKButton(window)
718 this->window = window;
721 int MenuEffectWindowOK::handle_event()
723 if(window->plugin_list)
724 window->result = window->list->get_selection_number(0, 0);
730 int MenuEffectWindowOK::keypress_event()
732 if(get_keypress() == RETURN)
740 MenuEffectWindowCancel::MenuEffectWindowCancel(MenuEffectWindow *window)
741 : BC_CancelButton(window)
743 this->window = window;
746 int MenuEffectWindowCancel::handle_event()
752 int MenuEffectWindowCancel::keypress_event()
754 if(get_keypress() == ESC)
762 MenuEffectWindowList::MenuEffectWindowList(MenuEffectWindow *window,
767 ArrayList<BC_ListBoxItem*> *plugin_list)
775 this->window = window;
778 int MenuEffectWindowList::handle_event()
780 window->result = get_selection_number(0, 0);
785 #define PROMPT_TEXT _("Set up effect panel and hit \"OK\"")
787 MenuEffectPrompt::MenuEffectPrompt(MWindow *mwindow)
788 : BC_Window(PROGRAM_NAME ": Effect Prompt",
789 mwindow->gui->get_abs_cursor_x(1) - 260 / 2,
790 mwindow->gui->get_abs_cursor_y(1) - 300,
791 MenuEffectPrompt::calculate_w(mwindow->gui),
792 MenuEffectPrompt::calculate_h(mwindow->gui),
793 MenuEffectPrompt::calculate_w(mwindow->gui),
794 MenuEffectPrompt::calculate_h(mwindow->gui),
801 int MenuEffectPrompt::calculate_w(BC_WindowBase *gui)
803 int w = BC_Title::calculate_w(gui, PROMPT_TEXT) + 10;
804 w = MAX(w, BC_OKButton::calculate_w() + BC_CancelButton::calculate_w() + 30);
808 int MenuEffectPrompt::calculate_h(BC_WindowBase *gui)
810 int h = BC_Title::calculate_h(gui, PROMPT_TEXT);
811 h += BC_OKButton::calculate_h() + 30;
816 void MenuEffectPrompt::create_objects()
820 add_subwindow(title = new BC_Title(x, y, PROMPT_TEXT));
821 add_subwindow(new BC_OKButton(this));
822 add_subwindow(new BC_CancelButton(this));