From 9f068afe02b674d17c146ed868ee7e050dd4876b Mon Sep 17 00:00:00 2001 From: Nikolaus Gullotta Date: Fri, 24 May 2019 14:10:38 -0500 Subject: [PATCH] initial dirty work on a state substitution dialog - lots of cleanup and imporvement needed --- gtk2_ardour/mixer_snapshot_dialog.cc | 7 +- .../mixer_snapshot_substitution_dialog.cc | 249 ++++++++++++++++++ .../mixer_snapshot_substitution_dialog.h | 48 ++++ libs/ardour/ardour/mixer_snapshot.h | 2 + libs/ardour/mixer_snapshot.cc | 8 +- 5 files changed, 309 insertions(+), 5 deletions(-) create mode 100644 gtk2_ardour/mixer_snapshot_substitution_dialog.cc create mode 100644 gtk2_ardour/mixer_snapshot_substitution_dialog.h diff --git a/gtk2_ardour/mixer_snapshot_dialog.cc b/gtk2_ardour/mixer_snapshot_dialog.cc index 853ab6d8f0..526f5d348f 100644 --- a/gtk2_ardour/mixer_snapshot_dialog.cc +++ b/gtk2_ardour/mixer_snapshot_dialog.cc @@ -33,6 +33,7 @@ #include "editor.h" #include "mixer_snapshot_dialog.h" +#include "mixer_snapshot_substitution_dialog.h" #include "utils.h" #include "pbd/basename.h" @@ -198,7 +199,11 @@ void MixerSnapshotDialog::popup_context_menu(int btn, int64_t time, TreeModel::i void MixerSnapshotDialog::load_snapshot(TreeModel::iterator& iter) { MixerSnapshot* snap = (*iter)[_columns.snapshot]; - snap->recall(); + + MixerSnapshotSubstitutionDialog* d = new MixerSnapshotSubstitutionDialog(snap); + d->show_all(); + // d->signal_response().connect(sigc::bind(sigc::mem_fun(*this, &MixerSnapshotDialog::sub_dialog_finished), d)); + // snap->recall(); } void MixerSnapshotDialog::rename_snapshot(TreeModel::iterator& iter) diff --git a/gtk2_ardour/mixer_snapshot_substitution_dialog.cc b/gtk2_ardour/mixer_snapshot_substitution_dialog.cc new file mode 100644 index 0000000000..1aa39a70ea --- /dev/null +++ b/gtk2_ardour/mixer_snapshot_substitution_dialog.cc @@ -0,0 +1,249 @@ +/* + Copyright (C) 2019 Nikolaus Gullotta + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include +#include + +#include +#include +#include + +#include "mixer_snapshot_substitution_dialog.h" + +#include "ardour/mixer_snapshot.h" +#include "ardour/utils.h" + +#include "pbd/i18n.h" + +using namespace ARDOUR; +using namespace Gtk; +using namespace PBD; +using namespace std; + +MixerSnapshotSubstitutionDialog::MixerSnapshotSubstitutionDialog(MixerSnapshot* snapshot) + : ArdourDialog (_("Substitutions"), true) + , _snapshot(snapshot) +{ + RouteList rl = _snapshot->get_session()->get_routelist(); + + Table* table = manage(new Table(rl.size(), 1)); + + int n = 0; + Label* dst = manage(new Label(_("Destination: "), ALIGN_CENTER, ALIGN_CENTER)); + Label* src = manage(new Label(_("Source: "), ALIGN_CENTER, ALIGN_CENTER)); + table->attach(*dst, 0, 1, n, n+1); + table->attach(*src, 1, 2, n, n+1); + n++; + + + for(RouteList::const_iterator it = rl.begin(); it != rl.end(); it++) { + boost::shared_ptr route = (*it); + + if(route) { + ComboBoxText* combo = manage(new ComboBoxText()); + fill_combo_box(combo, route->name()); + + Label* l = manage(new Label(route->name(), ALIGN_LEFT, ALIGN_CENTER, false)); + table->attach(*l, 0, 1, n, n+1); + table->attach(*combo, 1, 2, n, n+1); + + substitutions.push_back(route_combo(route, combo)); + } + n++; + } + + ComboBoxText* sel_combo = manage(new ComboBoxText()); + Label* sel = manage(new Label(_("All Selected: "))); + fill_combo_box(sel_combo, ""); + table->attach(*sel, 0, 1, n, n+1); + table->attach(*sel_combo, 1, 2, n, n+1); + n++; + + + add_button (Stock::CANCEL, RESPONSE_CANCEL); + add_button (Stock::APPLY, RESPONSE_ACCEPT); + set_default_response(RESPONSE_ACCEPT); + + get_vbox()->pack_start(*table, true, true); +} + +void MixerSnapshotSubstitutionDialog::fill_combo_box(ComboBoxText* box, const string route_name) +{ + box->append(" --- "); + box->set_active_text(" --- "); + + vector routes = _snapshot->get_routes(); + + for(vector::iterator i = routes.begin(); i != routes.end(); i++) { + string state_name = (*i).name; + box->append(state_name); + if(state_name == route_name) { + box->set_active_text(state_name); + } + } +} + +void MixerSnapshotSubstitutionDialog::on_response(int r) +{ + if(r == RESPONSE_CANCEL) { + close_self(); + return; + } + + vector dirty = _snapshot->get_routes(); + vector clean = _snapshot->get_routes(); + vector new_s; + vector del_s; + + if(r == RESPONSE_ACCEPT) { + for(vector::iterator c = substitutions.begin(); c != substitutions.end(); c++) { + string route_name = (*c).first->name(); + string subst_name = (*c).second->get_active_text(); + int n = 0; + for(vector::iterator s = dirty.begin(); s != dirty.end(); s++) { + MixerSnapshot::State state = (*s); + if(route_name == state.name) { + //state and substitution are matches + if(route_name == subst_name) { + break; + } + + //empty sub - erase it + if(subst_name == " --- ") { + del_s.push_back(state); + break; + } + } + if(subst_name == " --- ") { + break; + } + + bool route_state_exists = state_exists(route_name); + bool subst_state_exists = state_exists(subst_name); + + //state exists but we are picking a different source + if(route_name != subst_name) { + if(route_state_exists && subst_state_exists) { + XMLNode copy (get_state_by_name(subst_name).node); + sanitize_node(copy, route_name); + state.node = copy; + } + + //state did *not* exist, make it and add the substitute node + if(!route_state_exists && subst_state_exists) { + //copy the substitute node + XMLNode copy (get_state_by_name(subst_name).node); + sanitize_node(copy, route_name); + MixerSnapshot::State s { + "", + route_name, + copy + }; + + new_s.push_back(s); + } + } + n++; + } + } + } + + for(vector::iterator s = new_s.begin(); s != new_s.end(); s++) { + dirty.push_back((*s)); + } + + for(vector::iterator d = del_s.begin(); d != del_s.end(); d++) { + for(vector::iterator s = dirty.begin(); s != dirty.end(); s++) { + if((*d).id == (*s).id) { + dirty.erase(s); + s--; + break; + } + } + } + + for(vector::iterator s = dirty.begin(); s != dirty.end(); s++) { + cout << (*s).name << endl; + } + + _snapshot->set_route_states(dirty); + _snapshot->recall(); + _snapshot->set_route_states(clean); + close_self(); +} + +bool MixerSnapshotSubstitutionDialog::state_exists(const string name) +{ + vector routes = _snapshot->get_routes(); + + for(vector::iterator i = routes.begin(); i != routes.end(); i++) { + if((*i).name == name) { + return true; + } + } + return false; +} + +MixerSnapshot::State MixerSnapshotSubstitutionDialog::get_state_by_name(const string name) { + vector routes = _snapshot->get_routes(); + for(vector::iterator i = routes.begin(); i != routes.end(); i++) { + if((*i).name == name) { + return (*i); + } + } +} + +XMLNode& MixerSnapshotSubstitutionDialog::sanitize_node(XMLNode& node, const string route_name) +{ + //remove I/O + node.remove_node_and_delete("IO", "direction", "Input"); + node.remove_node_and_delete("IO", "direction", "Output"); + node.remove_node_and_delete("IO", "direction", "Output"); + + //remove diskwriter and reader + node.remove_node_and_delete("Processor", "type", "diskwriter"); + node.remove_node_and_delete("Processor", "type", "diskreader"); + + //remove any sidechain stuff + // node.remove_node_and_delete("Processor", "type", "sidechain"); + + //set node to destination's name + node.set_property(X_("name"), route_name); + + //unlink playlists + node.remove_property(X_("id")); + node.remove_property(X_("audio-playlist")); + + XMLNode* pi_node = find_named_node(node, X_("PresentationInfo")); + XMLNode* proc_node = find_named_node(node, X_("PresentationInfo")); + + if(pi_node) { + pi_node->remove_property(X_("order")); + } + + + XMLNodeList nlist = node.children(); + for(XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); niter++) { + if((*niter)->name() != "Processor") { + continue; + } + + (*niter)->remove_node_and_delete("Processor", "type", "sidechain"); + } + + return node; +} \ No newline at end of file diff --git a/gtk2_ardour/mixer_snapshot_substitution_dialog.h b/gtk2_ardour/mixer_snapshot_substitution_dialog.h new file mode 100644 index 0000000000..5460a75302 --- /dev/null +++ b/gtk2_ardour/mixer_snapshot_substitution_dialog.h @@ -0,0 +1,48 @@ +/* + Copyright (C) 2019 Nikolaus Gullotta + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef __ardour_mixer_snapshot_substitution_dialog_h__ +#define __ardour_mixer_snapshot_substitution_dialog_h__ + +#include +#include +#include + +#include "ardour_dialog.h" + +#include "ardour/mixer_snapshot.h" + +typedef std::pair, Gtk::ComboBoxText*> route_combo; + +class MixerSnapshotSubstitutionDialog : public ArdourDialog +{ +public: + MixerSnapshotSubstitutionDialog(ARDOUR::MixerSnapshot*); +private: + bool state_exists(const std::string); + ARDOUR::MixerSnapshot::State get_state_by_name(const std::string); + void fill_combo_box(Gtk::ComboBoxText*, const std::string); + void on_response(int); + XMLNode& sanitize_node(XMLNode&, const std::string); + + std::vector substitutions; + + ARDOUR::MixerSnapshot* _snapshot; +}; + +#endif /* __ardour_mixer_snapshot_substitution_dialog_h__ */ \ No newline at end of file diff --git a/libs/ardour/ardour/mixer_snapshot.h b/libs/ardour/ardour/mixer_snapshot.h index 5f1530aae6..f045da57d5 100644 --- a/libs/ardour/ardour/mixer_snapshot.h +++ b/libs/ardour/ardour/mixer_snapshot.h @@ -105,6 +105,8 @@ class LIBARDOUR_API MixerSnapshot std::string get_last_modified_with() {return last_modified_with;}; void set_last_modified_with(std::string new_modified_with) {last_modified_with = new_modified_with;}; + void set_route_states(std::vector states) { route_states = states;}; + private: ARDOUR::Session* _session; diff --git a/libs/ardour/mixer_snapshot.cc b/libs/ardour/mixer_snapshot.cc index e3c2093b3f..ff3d6c48ac 100644 --- a/libs/ardour/mixer_snapshot.cc +++ b/libs/ardour/mixer_snapshot.cc @@ -330,17 +330,17 @@ void MixerSnapshot::recall() for(vector::const_iterator i = route_states.begin(); i != route_states.end(); i++) { State state = (*i); - boost::shared_ptr route = _session->route_by_id(PBD::ID(state.id)); + // boost::shared_ptr route;// = _session->route_by_id(PBD::ID(state.id)); - if(!route) { - route = _session->route_by_name(state.name); - } + boost::shared_ptr route = _session->route_by_name(state.name); if(route) { + printf("Setting state %s for route %s\n", state.name.c_str(), route->name().c_str()); XMLNode& bfr = route->get_state(); route->set_state(sanitize_node(state.node), PBD::Stateful::loading_state_version); reassign_masters(route, state.node); _session->add_command(new MementoCommand((*route), &bfr, &route->get_state())); + route->emit_pending_signals(); } }