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_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)
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,
527 mwindow->save_backup();
528 mwindow->undo->update_undo_after(title, LOAD_ALL);
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();
536 mwindow->awindow->gui->async_update_assets();
539 for(int i = 0; i < assets.total; i++)
540 assets.values[i]->Garbage::remove_user();
543 default_asset->Garbage::remove_user();
552 MenuEffectItem::MenuEffectItem(MenuEffects *menueffect, const char *string)
553 : BC_MenuItem(string)
555 this->menueffect = menueffect;
557 int MenuEffectItem::handle_event()
559 menueffect->thread->set_title(get_text());
560 menueffect->thread->start();
575 MenuEffectWindow::MenuEffectWindow(MWindow *mwindow,
576 MenuEffectThread *menueffects,
577 ArrayList<BC_ListBoxItem*> *plugin_list,
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,
590 this->menueffects = menueffects;
591 this->plugin_list = plugin_list;
593 this->mwindow = mwindow;
599 MenuEffectWindow::~MenuEffectWindow()
601 lock_window("MenuEffectWindow::~MenuEffectWindow");
608 void MenuEffectWindow::create_objects()
612 mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
614 lock_window("MenuEffectWindow::create_objects");
615 // only add the list if needed
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,
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:"))));
636 x = mwindow->theme->menueffect_tools_x;
637 y = mwindow->theme->menueffect_tools_y;
638 format_tools = new FormatTools(mwindow,
641 format_tools->create_objects(x,
651 &menueffects->strategy,
654 loadmode = new LoadMode(mwindow, this, x, y, &menueffects->load_mode, 1);
655 loadmode->create_objects();
657 add_subwindow(new MenuEffectWindowOK(this));
658 add_subwindow(new MenuEffectWindowCancel(this));
663 int MenuEffectWindow::resize_event(int w, int h)
665 mwindow->session->menueffect_w = w;
666 mwindow->session->menueffect_h = h;
667 mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0);
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);
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);
690 MenuEffectWindowOK::MenuEffectWindowOK(MenuEffectWindow *window)
691 : BC_OKButton(window)
693 this->window = window;
696 int MenuEffectWindowOK::handle_event()
698 if(window->plugin_list)
699 window->result = window->list->get_selection_number(0, 0);
705 int MenuEffectWindowOK::keypress_event()
707 if(get_keypress() == RETURN)
715 MenuEffectWindowCancel::MenuEffectWindowCancel(MenuEffectWindow *window)
716 : BC_CancelButton(window)
718 this->window = window;
721 int MenuEffectWindowCancel::handle_event()
727 int MenuEffectWindowCancel::keypress_event()
729 if(get_keypress() == ESC)
737 MenuEffectWindowList::MenuEffectWindowList(MenuEffectWindow *window,
742 ArrayList<BC_ListBoxItem*> *plugin_list)
750 this->window = window;
753 int MenuEffectWindowList::handle_event()
755 window->result = get_selection_number(0, 0);
760 #define PROMPT_TEXT _("Set up effect panel and hit \"OK\"")
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),
776 int MenuEffectPrompt::calculate_w(BC_WindowBase *gui)
778 int w = BC_Title::calculate_w(gui, PROMPT_TEXT) + 10;
779 w = MAX(w, BC_OKButton::calculate_w() + BC_CancelButton::calculate_w() + 30);
783 int MenuEffectPrompt::calculate_h(BC_WindowBase *gui)
785 int h = BC_Title::calculate_h(gui, PROMPT_TEXT);
786 h += BC_OKButton::calculate_h() + 30;
791 void MenuEffectPrompt::create_objects()
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));