X-Git-Url: https://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fcinelerra%2Fmenueffects.C;fp=cinelerra-5.1%2Fcinelerra%2Fmenueffects.C;h=6705e4006e37f3a84a8f19e67b7cfd288559ad24;hb=30bdb85eb33a8ee7ba675038a86c6be59c43d7bd;hp=0000000000000000000000000000000000000000;hpb=52fcc46226f9df46f9ce9d0566dc568455a7db0b;p=goodguy%2Fhistory.git diff --git a/cinelerra-5.1/cinelerra/menueffects.C b/cinelerra-5.1/cinelerra/menueffects.C new file mode 100644 index 00000000..6705e400 --- /dev/null +++ b/cinelerra-5.1/cinelerra/menueffects.C @@ -0,0 +1,814 @@ + +/* + * CINELERRA + * Copyright (C) 2010 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "asset.h" +#include "awindow.h" +#include "awindowgui.h" +#include "clip.h" +#include "confirmsave.h" +#include "bchash.h" +#include "edl.h" +#include "edlsession.h" +#include "errorbox.h" +#include "file.h" +#include "formatcheck.h" +#include "indexfile.h" +#include "keyframe.h" +#include "keys.h" +#include "labels.h" +#include "language.h" +#include "loadmode.h" +#include "localsession.h" +#include "mainmenu.h" +#include "mainsession.h" +#include "mainundo.h" +#include "mwindow.h" +#include "mwindowgui.h" +#include "menueffects.h" +#include "playbackengine.h" +#include "pluginarray.h" +#include "pluginserver.h" +#include "preferences.h" +#include "render.h" +#include "sighandler.h" +#include "theme.h" +#include "tracks.h" + + + +MenuEffects::MenuEffects(MWindow *mwindow) + : BC_MenuItem(_("Render effect...")) +{ + this->mwindow = mwindow; +} + +MenuEffects::~MenuEffects() +{ +} + + +int MenuEffects::handle_event() +{ + thread->set_title(""); + thread->start(); + return 1; +} + + + + + +MenuEffectPacket::MenuEffectPacket(char *path, int64_t start, int64_t end) +{ + this->start = start; + this->end = end; + strcpy(this->path, path); +} + +MenuEffectPacket::~MenuEffectPacket() +{ +} + + + + + + +MenuEffectThread::MenuEffectThread(MWindow *mwindow, MenuEffects *menu_item) +{ + this->mwindow = mwindow; + this->menu_item = menu_item; + title[0] = 0; + dead_plugins = new ArrayList; +} + +MenuEffectThread::~MenuEffectThread() +{ + delete dead_plugins; +} + + + + + +int MenuEffectThread::set_title(const char *title) +{ + strcpy(this->title, title); + return 0; +} + +// for recent effect menu items and running new effects +// prompts for an effect if title is blank +void MenuEffectThread::run() +{ + for(int i = 0; i < dead_plugins->size(); i++) + { + delete dead_plugins->get(i); + } + dead_plugins->remove_all(); + + + + +// get stuff from main window + ArrayList *plugindb = mwindow->plugindb; + BC_Hash *defaults = mwindow->defaults; + ArrayList plugin_list; + ArrayList local_plugindb; + char string[1024]; + int result = 0; +// Default configuration + Asset *default_asset = new Asset; +// Output + ArrayList assets; + + +// check for recordable tracks + if(!get_recordable_tracks(default_asset)) + { + sprintf(string, _("No recordable tracks specified.")); + ErrorBox error(_(PROGRAM_NAME ": Error")); + error.create_objects(string); + error.run_window(); + default_asset->Garbage::remove_user(); + return; + } + +// check for plugins + if(!plugindb->total) + { + sprintf(string, _("No plugins available.")); + ErrorBox error(_(PROGRAM_NAME ": Error")); + error.create_objects(string); + error.run_window(); + default_asset->Garbage::remove_user(); + return; + } + + +// get default attributes for output file +// used after completion + get_derived_attributes(default_asset, defaults); +// to_tracks = defaults->get("RENDER_EFFECT_TO_TRACKS", 1); + load_mode = defaults->get("RENDER_EFFECT_LOADMODE", LOADMODE_PASTE); + strategy = defaults->get("RENDER_EFFECT_STRATEGY", SINGLE_PASS); + +// get plugin information + int need_plugin; + if(!strlen(title)) + need_plugin = 1; + else + need_plugin = 0; + +// generate a list of plugins for the window + if(need_plugin) + { + mwindow->search_plugindb(default_asset->audio_data, + default_asset->video_data, + -1, + 0, + 0, + local_plugindb); + + for(int i = 0; i < local_plugindb.total; i++) + { + plugin_list.append(new BC_ListBoxItem(_(local_plugindb.values[i]->title))); + } + } + +// find out which effect to run and get output file + int plugin_number, format_error = 0; + + do + { + { + MenuEffectWindow window(mwindow, + this, + need_plugin ? &plugin_list : 0, + default_asset); + window.create_objects(); + result = window.run_window(); + plugin_number = window.result; + } + + if(!result) + { + FormatCheck format_check(default_asset); + format_error = format_check.check_format(); + } + }while(format_error && !result); + +// save defaults + save_derived_attributes(default_asset, defaults); + defaults->update("RENDER_EFFECT_LOADMODE", load_mode); + defaults->update("RENDER_EFFECT_STRATEGY", strategy); + mwindow->save_defaults(); + +// get plugin server to use and delete the plugin list + PluginServer *plugin_server = 0; + PluginServer *plugin = 0; + if(need_plugin) + { + plugin_list.remove_all_objects(); + if(plugin_number > -1) + { + plugin_server = local_plugindb.values[plugin_number]; + strcpy(title, plugin_server->title); + } + } + else + { + for(int i = 0; i < plugindb->total && !plugin_server; i++) + { + if(!strcmp(plugindb->values[i]->title, title)) + { + plugin_server = plugindb->values[i]; + plugin_number = i; + } + } + } + +// Update the most recently used effects and copy the plugin server. + if(plugin_server) + { + plugin = new PluginServer(*plugin_server); + fix_menu(title); + } + + if(!result && !strlen(default_asset->path)) + { + result = 1; // no output path given + ErrorBox error(_(PROGRAM_NAME ": Error")); + error.create_objects(_("No output file specified.")); + error.run_window(); + } + + if(!result && plugin_number < 0) + { + result = 1; // no output path given + ErrorBox error(_(PROGRAM_NAME ": Error")); + error.create_objects(_("No effect selected.")); + error.run_window(); + } + +// Configuration for realtime plugins. + KeyFrame plugin_data; + +// get selection to render +// Range + double total_start, total_end; + + total_start = mwindow->edl->local_session->get_selectionstart(); + + + if(mwindow->edl->local_session->get_selectionend() == + mwindow->edl->local_session->get_selectionstart()) + total_end = mwindow->edl->tracks->total_playable_length(); + else + total_end = mwindow->edl->local_session->get_selectionend(); + + + +// get native units for range + total_start = to_units(total_start, 0); + total_end = to_units(total_end, 1); + + + +// Trick boundaries in case of a non-realtime synthesis plugin + if(plugin && + !plugin->realtime && + total_end == total_start) total_end = total_start + 1; + +// Units are now in the track's units. + int64_t total_length = (int64_t)total_end - (int64_t)total_start; +// length of output file + + if(!result && total_length <= 0) + { + result = 1; // no output path given + ErrorBox error(_(PROGRAM_NAME ": Error")); + error.create_objects(_("No selected range to process.")); + error.run_window(); + } + +// ========================= get keyframe from user + if(!result) + { +// ========================= realtime plugin +// no get_parameters + if(plugin->realtime) + { +// Open a prompt GUI + MenuEffectPrompt prompt(mwindow); + prompt.create_objects(); + char title[BCTEXTLEN]; + sprintf(title, _(PROGRAM_NAME ": %s"), plugin->title); + +// Open the plugin GUI + plugin->set_mwindow(mwindow); + plugin->set_keyframe(&plugin_data); + plugin->set_prompt(&prompt); + plugin->open_plugin(0, mwindow->preferences, mwindow->edl, 0); +// Must set parameters since there is no plugin object to draw from. + plugin->get_parameters((int64_t)total_start, + (int64_t)total_end, + 1); + plugin->show_gui(); + +// wait for user input + result = prompt.run_window(); + +// Close plugin. + plugin->save_data(&plugin_data); + plugin->hide_gui(); + +// Can't delete here. + dead_plugins->append(plugin); + default_asset->sample_rate = mwindow->edl->session->sample_rate; + default_asset->frame_rate = mwindow->edl->session->frame_rate; + realtime = 1; + } + else +// ============================non realtime plugin + { + plugin->set_mwindow(mwindow); + plugin->open_plugin(0, mwindow->preferences, mwindow->edl, 0); + result = plugin->get_parameters((int64_t)total_start, + (int64_t)total_end, + get_recordable_tracks(default_asset)); +// some plugins can change the sample rate and the frame rate + + + if(!result) + { + default_asset->sample_rate = plugin->get_samplerate(); + default_asset->frame_rate = plugin->get_framerate(); + } + delete plugin; + realtime = 0; + } + +// Should take from first recordable track + default_asset->width = mwindow->edl->session->output_w; + default_asset->height = mwindow->edl->session->output_h; + } + +// Process the total length in fragments + ArrayList packets; + if(!result) + { + Label *current_label = mwindow->edl->labels->first; + mwindow->stop_brender(); + + int current_number; + int number_start; + int total_digits; + Render::get_starting_number(default_asset->path, + current_number, + number_start, + total_digits); + + + +// Construct all packets for single overwrite confirmation + for(int64_t fragment_start = (int64_t)total_start, fragment_end; + fragment_start < (int64_t)total_end; + fragment_start = fragment_end) + { +// Get fragment end + if(strategy == FILE_PER_LABEL || strategy == FILE_PER_LABEL_FARM) + { + while(current_label && + to_units(current_label->position, 0) <= fragment_start) + current_label = current_label->next; + if(!current_label) + fragment_end = (int64_t)total_end; + else + fragment_end = to_units(current_label->position, 0); + } + else + { + fragment_end = (int64_t)total_end; + } + +// Get path + char path[BCTEXTLEN]; + if(strategy == FILE_PER_LABEL || strategy == FILE_PER_LABEL_FARM) + Render::create_filename(path, + default_asset->path, + current_number, + total_digits, + number_start); + else + strcpy(path, default_asset->path); + current_number++; + + MenuEffectPacket *packet = new MenuEffectPacket(path, + fragment_start, + fragment_end); + packets.append(packet); + } + + +// Test existence of files + ArrayList paths; + for(int i = 0; i < packets.total; i++) + { + paths.append(packets.values[i]->path); + } + result = ConfirmSave::test_files(mwindow, &paths); + paths.remove_all(); + } + + + + for(int current_packet = 0; + current_packet < packets.total && !result; + current_packet++) + { + Asset *asset = new Asset(*default_asset); + MenuEffectPacket *packet = packets.values[current_packet]; + int64_t fragment_start = packet->start; + int64_t fragment_end = packet->end; + strcpy(asset->path, packet->path); + + assets.append(asset); + File *file = new File; + +// Open the output file after getting the information because the sample rate +// is needed here. + if(!result) + { +// open output file in write mode + file->set_processors(mwindow->preferences->processors); + if(file->open_file(mwindow->preferences, + asset, + 0, + 1)) + { +// open failed + sprintf(string, _("Couldn't open %s"), asset->path); + ErrorBox error(_(PROGRAM_NAME ": Error")); + error.create_objects(string); + error.run_window(); + result = 1; + } + else + { + mwindow->sighandler->push_file(file); + IndexFile::delete_index(mwindow->preferences, + asset); + } + } + +// run plugins + if(!result) + { +// position file + PluginArray *plugin_array; + plugin_array = create_plugin_array(); + + plugin_array->start_plugins(mwindow, + mwindow->edl, + plugin_server, + &plugin_data, + fragment_start, + fragment_end, + file); + plugin_array->run_plugins(); + + plugin_array->stop_plugins(); + mwindow->sighandler->pull_file(file); + file->close_file(); + asset->audio_length = file->asset->audio_length; + asset->video_length = file->asset->video_length; + delete plugin_array; + } + + delete file; + } + + packets.remove_all_objects(); + +// paste output to tracks + if(!result && load_mode != LOADMODE_NOTHING) + { + mwindow->gui->lock_window("MenuEffectThread::run"); + + mwindow->undo->update_undo_before("", 0); + if(load_mode == LOADMODE_PASTE) + mwindow->clear(0); + + + mwindow->load_assets(&assets, + -1, + load_mode, + 0, + 0, + mwindow->edl->session->labels_follow_edits, + mwindow->edl->session->plugins_follow_edits, + mwindow->edl->session->autos_follow_edits, + 0); // overwrite + + mwindow->save_backup(); + mwindow->undo->update_undo_after(title, LOAD_ALL); + + + + mwindow->restart_brender(); + mwindow->update_plugin_guis(); + mwindow->gui->update(1, + 2, + 1, + 1, + 1, + 1, + 0); + mwindow->sync_parameters(CHANGE_ALL); + mwindow->gui->unlock_window(); + + mwindow->awindow->gui->async_update_assets(); + } + + for(int i = 0; i < assets.total; i++) + assets.values[i]->Garbage::remove_user(); + assets.remove_all(); + + default_asset->Garbage::remove_user(); +} + + + + + + + +MenuEffectItem::MenuEffectItem(MenuEffects *menueffect, const char *string) + : BC_MenuItem(string) +{ + this->menueffect = menueffect; +} +int MenuEffectItem::handle_event() +{ + menueffect->thread->set_title(get_text()); + menueffect->thread->start(); + return 1; +} + + + + + + + + + + + + +MenuEffectWindow::MenuEffectWindow(MWindow *mwindow, + MenuEffectThread *menueffects, + ArrayList *plugin_list, + Asset *asset) + : BC_Window(_(PROGRAM_NAME ": Render effect"), + mwindow->gui->get_abs_cursor_x(1), + mwindow->gui->get_abs_cursor_y(1) - mwindow->session->menueffect_h / 2, + mwindow->session->menueffect_w, + mwindow->session->menueffect_h, + 580, + 350, + 1, + 0, + 1) +{ + this->menueffects = menueffects; + this->plugin_list = plugin_list; + this->asset = asset; + this->mwindow = mwindow; + file_title = 0; + format_tools = 0; + loadmode = 0; +} + +MenuEffectWindow::~MenuEffectWindow() +{ + lock_window("MenuEffectWindow::~MenuEffectWindow"); + delete format_tools; + unlock_window(); +} + + + +void MenuEffectWindow::create_objects() +{ + int x, y; + result = -1; + mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0); + + lock_window("MenuEffectWindow::create_objects"); +// only add the list if needed + if(plugin_list) + { + add_subwindow(list_title = new BC_Title(mwindow->theme->menueffect_list_x, + mwindow->theme->menueffect_list_y, + _("Select an effect"))); + add_subwindow(list = new MenuEffectWindowList(this, + mwindow->theme->menueffect_list_x, + mwindow->theme->menueffect_list_y + list_title->get_h() + 5, + mwindow->theme->menueffect_list_w, + mwindow->theme->menueffect_list_h - list_title->get_h() - 5, + plugin_list)); + } + + add_subwindow(file_title = new BC_Title( + mwindow->theme->menueffect_file_x, + mwindow->theme->menueffect_file_y, + (char*)((menueffects->strategy == FILE_PER_LABEL || menueffects->strategy == FILE_PER_LABEL_FARM) ? + _("Select the first file to render to:") : + _("Select a file to render to:")))); + + x = mwindow->theme->menueffect_tools_x; + y = mwindow->theme->menueffect_tools_y; + format_tools = new FormatTools(mwindow, + this, + asset); + format_tools->create_objects(x, + y, + asset->audio_data, + asset->video_data, + 0, + 0, + 0, + 1, + 0, + 0, + &menueffects->strategy, + 0); + + loadmode = new LoadMode(mwindow, this, x, y, &menueffects->load_mode, 1); + loadmode->create_objects(); + + add_subwindow(new MenuEffectWindowOK(this)); + add_subwindow(new MenuEffectWindowCancel(this)); + show_window(); + unlock_window(); +} + +int MenuEffectWindow::resize_event(int w, int h) +{ + mwindow->session->menueffect_w = w; + mwindow->session->menueffect_h = h; + mwindow->theme->get_menueffect_sizes(plugin_list ? 1 : 0); + + if(plugin_list) + { + list_title->reposition_window(mwindow->theme->menueffect_list_x, + mwindow->theme->menueffect_list_y); + list->reposition_window(mwindow->theme->menueffect_list_x, + mwindow->theme->menueffect_list_y + list_title->get_h() + 5, + mwindow->theme->menueffect_list_w, + mwindow->theme->menueffect_list_h - list_title->get_h() - 5); + } + + if(file_title) file_title->reposition_window(mwindow->theme->menueffect_file_x, + mwindow->theme->menueffect_file_y); + int x = mwindow->theme->menueffect_tools_x; + int y = mwindow->theme->menueffect_tools_y; + if(format_tools) format_tools->reposition_window(x, y); + if(loadmode) loadmode->reposition_window(x, y); + return 0; +} + + + +MenuEffectWindowOK::MenuEffectWindowOK(MenuEffectWindow *window) + : BC_OKButton(window) +{ + this->window = window; +} + +int MenuEffectWindowOK::handle_event() +{ + if(window->plugin_list) + window->result = window->list->get_selection_number(0, 0); + + window->set_done(0); + return 1; +} + +int MenuEffectWindowOK::keypress_event() +{ + if(get_keypress() == RETURN) + { + handle_event(); + return 1; + } + return 0; +} + +MenuEffectWindowCancel::MenuEffectWindowCancel(MenuEffectWindow *window) + : BC_CancelButton(window) +{ + this->window = window; +} + +int MenuEffectWindowCancel::handle_event() +{ + window->set_done(1); + return 1; +} + +int MenuEffectWindowCancel::keypress_event() +{ + if(get_keypress() == ESC) + { + handle_event(); + return 1; + } + return 0; +} + +MenuEffectWindowList::MenuEffectWindowList(MenuEffectWindow *window, + int x, + int y, + int w, + int h, + ArrayList *plugin_list) + : BC_ListBox(x, + y, + w, + h, + LISTBOX_TEXT, + plugin_list) +{ + this->window = window; +} + +int MenuEffectWindowList::handle_event() +{ + window->result = get_selection_number(0, 0); + window->set_done(0); + return 1; +} + +#define PROMPT_TEXT _("Set up effect panel and hit \"OK\"") + +MenuEffectPrompt::MenuEffectPrompt(MWindow *mwindow) + : BC_Window(_(PROGRAM_NAME ": Effect Prompt"), + mwindow->gui->get_abs_cursor_x(1) - 260 / 2, + mwindow->gui->get_abs_cursor_y(1) - 300, + MenuEffectPrompt::calculate_w(mwindow->gui), + MenuEffectPrompt::calculate_h(mwindow->gui), + MenuEffectPrompt::calculate_w(mwindow->gui), + MenuEffectPrompt::calculate_h(mwindow->gui), + 0, + 0, + 1) +{ +} + +int MenuEffectPrompt::calculate_w(BC_WindowBase *gui) +{ + int w = BC_Title::calculate_w(gui, PROMPT_TEXT) + 10; + w = MAX(w, BC_OKButton::calculate_w() + BC_CancelButton::calculate_w() + 30); + return w; +} + +int MenuEffectPrompt::calculate_h(BC_WindowBase *gui) +{ + int h = BC_Title::calculate_h(gui, PROMPT_TEXT); + h += BC_OKButton::calculate_h() + 30; + return h; +} + + +void MenuEffectPrompt::create_objects() +{ + int x = 10, y = 10; + BC_Title *title; + add_subwindow(title = new BC_Title(x, y, PROMPT_TEXT)); + add_subwindow(new BC_OKButton(this)); + add_subwindow(new BC_CancelButton(this)); + show_window(); + raise_window(); +} +