diff --git a/libs/surfaces/console1/c1_plugin_operations.cc b/libs/surfaces/console1/c1_plugin_operations.cc index b0e97f67f2..5641cb3f64 100644 --- a/libs/surfaces/console1/c1_plugin_operations.cc +++ b/libs/surfaces/console1/c1_plugin_operations.cc @@ -27,6 +27,7 @@ #include "glibmm-2.4/glibmm/main.h" #include "glibmm-2.4/glibmm/miscutils.h" #include "pbd/debug.h" +#include "pbd/i18n.h" #include "ardour/filesystem_paths.h" #include "ardour/plugin_insert.h" @@ -43,35 +44,50 @@ using namespace std; namespace ArdourSurface { -uint32_t -Console1::load_mappings () +bool +Console1::ensure_config_dir () { - uint32_t i = 0; - std::string path = Glib::build_filename (user_config_directory (), "c1mappings"); - GError* error; + std::string path = Glib::build_filename (user_config_directory (), config_dir_name); + GError* error = 0; GFile* dir = g_file_new_for_path (path.c_str ()); if (!g_file_test (path.c_str (), G_FILE_TEST_IS_DIR)) { g_file_make_directory (dir, NULL, &error); } - const gchar* fileName; + return error == 0 || error->code == 0; +} + +uint32_t +Console1::load_mappings () +{ + uint32_t i = 0; + if (!ensure_config_dir ()) + return 1; + + std::string path = Glib::build_filename (user_config_directory (), config_dir_name); + const gchar* file_name; GDir* gdir = g_dir_open (path.c_str (), 0, NULL); if (gdir == NULL) return 0; - while ((fileName = g_dir_read_name (gdir)) != NULL) { - // if (!g_str_has_suffix (name, ".remmina")) - // continue; + while ((file_name = g_dir_read_name (gdir)) != NULL) { + if (!g_str_has_suffix (file_name, ".xml")) + continue; DEBUG_TRACE (DEBUG::Console1, - string_compose ("Console1::load_mappings - found mapping file: '%1'\n", fileName)); + string_compose ("Console1::load_mappings - found mapping file: '%1'\n", file_name)); - std::string filePath = Glib::build_filename (path, fileName); - FILE* fin = g_fopen (filePath.c_str (), "r"); - if (fin) { - DEBUG_TRACE (DEBUG::Console1, - string_compose ("Console1::load_mappings - opened mapping file: '%1'\n", filePath)); - load_mapping (fin); - fclose (fin); + std::string file_path = Glib::build_filename (path, file_name); + XMLTree tree; + XMLNode* mapping_xml; + if (tree.read (file_path)) { + mapping_xml = new XMLNode (*(tree.root ())); + } else { + warning << string_compose (_ ("Could not understand XML file %1"), file_path) << endmsg; } + if (mapping_xml) { + DEBUG_TRACE (DEBUG::Console1, + string_compose ("Console1::load_mappings - opened mapping file: '%1'\n", file_path)); + load_mapping (mapping_xml); + } ++i; } DEBUG_TRACE (DEBUG::Console1, string_compose ("Console1::load_mappings - found %1 mapping files\n", i)); @@ -80,54 +96,98 @@ Console1::load_mappings () } bool -Console1::load_mapping (FILE* fin) +Console1::load_mapping (XMLNode* mapping_xml) { - char tmp[1024]; + // char tmp[1024]; PluginMapping pm; - while (fgets (tmp, 1024, fin) != NULL) { - istringstream line (tmp); - std::string token; - vector strings; - while (getline (line, token, ';')) { - boost::algorithm::trim (token); - strings.push_back (std::move (token)); - } - if (strings.size () < 2) - continue; - DEBUG_TRACE (DEBUG::Console1, - string_compose ("Console1::load_mapping - Name: '%1', Val1: '%2', Val2: '%3' \n", - strings.at (0), - strings.at (1), - strings.size () > 2 ? strings.at (2) : "")); - if (strings.at (0) == "ID") { - pm.id = strings.at (1); - } else if (strings.at (0) == "NAME") { - pm.name = strings.at (1); - } else { - try { - uint32_t index = std::stoi (strings.at (0)); - // Only store complete mappings: Indey, Name, ControllerId - if (strings.size () < 3) - continue; - PluginParameterMapping parmap; - parmap.paramIndex = index; - parmap.name = strings.at (1); - ControllerMap::const_iterator m = controllerMap.find (strings.at (2)); - if (m == controllerMap.end ()) - continue; - parmap.controllerId = m->second; - pm.parameters[index] = std::move (parmap); - } catch (std::invalid_argument&) { - continue; + const XMLNodeList& nlist = mapping_xml->children (); + + mapping_xml->get_property ("ID", pm.id); + mapping_xml->get_property ("NAME", pm.name); + + XMLNodeConstIterator i; + for (i = nlist.begin (); i != nlist.end (); ++i) { + std::string param_id; + std::string param_type; + std::string param_name; + std::string param_mapping; + + (*i)->get_property ("id", param_id); + uint32_t index = std::stoi (param_id); + + (*i)->get_property ("type", param_type); + + + + const XMLNodeList& plist = (*i)->children (); + + XMLNodeConstIterator j; + for (j = plist.begin (); j != plist.end (); ++j) { + if ((*j)->name () == "name") { + param_name = (*j)->child_content (); + } else if ((*j)->name () == "mapping") { + param_mapping = (*j)->child_content (); } } + if (!param_mapping.empty ()) { + PluginParameterMapping parmap; + parmap.paramIndex = index; + parmap.name = param_name; + ControllerMap::const_iterator m = controllerMap.find (param_mapping); + if (m == controllerMap.end ()) + continue; + parmap.controllerId = m->second; + parmap.is_switch = (param_type == "switch"); + pm.parameters[index] = std::move (parmap); + pluginMappingMap[pm.id] = pm; + } } - pluginMappingMap[pm.id] = pm; return true; } +void +Console1::create_mapping (const std::shared_ptr proc, const std::shared_ptr plugin) +{ + XMLTree* tree = new XMLTree (); + XMLNode node = XMLNode ("c1plugin-mapping"); + node.set_property ("ID", plugin->unique_id ()); + node.set_property ("NAME", plugin->name ()); + int32_t n_controls = -1; + + set p = proc->what_can_be_automated (); + for (set::iterator j = p.begin (); j != p.end (); ++j) { + ++n_controls; + std::string n = proc->describe_parameter (*j); + DEBUG_TRACE (DEBUG::Console1, string_compose ("Plugin parameter %1: %2\n", n_controls, n)); + if (n == "hidden") { + continue; + } + XMLNode param = XMLNode ("param-mapping"); + param.set_property ("id", n_controls); + XMLNode name = XMLNode ("name"); + XMLNode c = XMLNode ("c", plugin->parameter_label (n_controls).c_str ()); + name.add_child_copy (c); + XMLNode mapping = XMLNode ("mapping"); + mapping.set_property ("shift", "false"); + param.add_child_copy (name); + param.add_child_copy (mapping); + node.add_child_copy (param); + } + + tree->set_root (&node); + + if (!ensure_config_dir ()) + return; + + std::string filename = Glib::build_filename ( + user_config_directory (), config_dir_name, string_compose ("%1.%2", plugin->unique_id (), "xml")); + + tree->set_filename (filename); + tree->write (); +} + bool -Console1::select_plugin (const uint32_t plugin_index) +Console1::select_plugin (const int32_t plugin_index) { DEBUG_TRACE (DEBUG::Console1, "Console1::select_plugin\n"); if (current_plugin_index == plugin_index) { @@ -135,7 +195,11 @@ Console1::select_plugin (const uint32_t plugin_index) if (!r) { return false; } +#ifdef MIXBUS + std::shared_ptr proc = r->nth_plugin (selected_intern_plugin_index); +#else std::shared_ptr proc = r->nth_plugin (plugin_index); +#endif if (!proc) { return false; } @@ -147,20 +211,19 @@ Console1::select_plugin (const uint32_t plugin_index) return false; plugin_insert->ToggleUI (); return true; - } - if (map_select_plugin (plugin_index)) { + } else if (map_select_plugin (plugin_index)) { return true; } return false; } bool -Console1::map_select_plugin (const uint32_t plugin_index) +Console1::map_select_plugin (const int32_t plugin_index) { DEBUG_TRACE (DEBUG::Console1, "map_select_plugin())\n"); if (spill_plugins (plugin_index)) { for (uint32_t i = 0; i < bank_size; ++i) { - if (i == plugin_index) { + if ((int)i == plugin_index) { start_blinking (ControllerID (FOCUS1 + i)); } else if (i != current_strippable_index) { stop_blinking (ControllerID (FOCUS1 + i)); @@ -169,21 +232,15 @@ Console1::map_select_plugin (const uint32_t plugin_index) current_plugin_index = plugin_index; return true; } else { - get_button (ControllerID (FOCUS1 + plugin_index))->set_led_state (plugin_index == current_strippable_index); + get_button (ControllerID (FOCUS1 + plugin_index)) + ->set_led_state (plugin_index == (int)current_strippable_index); } return false; } -bool -Console1::spill_plugins (const uint32_t plugin_index) +void +Console1::remove_plugin_operations () { - DEBUG_TRACE (DEBUG::Console1, string_compose ("spill_plugins(%1)\n", plugin_index)); - bool mapping_found = false; - std::shared_ptr r = std::dynamic_pointer_cast (_current_stripable); - if (!r) { - return false; - } - plugin_connections.drop_connections (); for (auto& e : encoders) { @@ -198,21 +255,58 @@ Console1::spill_plugins (const uint32_t plugin_index) c.second->set_plugin_action (0); c.second->set_led_state (false); } +} - std::shared_ptr proc = r->nth_plugin (plugin_index); - if (!proc) { - return false; +std::shared_ptr +Console1::find_plugin (const int32_t plugin_index) +{ + int32_t int_plugin_index = -1; + int32_t ext_plugin_index = -1; + std::shared_ptr proc; + DEBUG_TRACE (DEBUG::Console1, string_compose ("find_plugin(%1)\n", plugin_index)); + std::shared_ptr r = std::dynamic_pointer_cast (_current_stripable); + if (!r) { + return proc; } - if (!proc->display_to_user ()) { - return false; + remove_plugin_operations (); + + while ((ext_plugin_index < plugin_index) && (int_plugin_index < (int)bank_size)) { + ++int_plugin_index; + + proc = r->nth_plugin (int_plugin_index); + if (!proc) { + continue; + ; + } + if (!proc->display_to_user ()) { + continue; + } + +#ifdef MIXBUS + /* don't show channelstrip plugins */ + if (std::dynamic_pointer_cast (proc)->is_channelstrip ()) { + continue; + } +#endif + ++ext_plugin_index; } #ifdef MIXBUS - /* don't show channelstrip plugins, use "well known" */ - if (std::dynamic_pointer_cast (proc)->is_channelstrip ()) { - continue; - } + selected_intern_plugin_index = int_plugin_index; #endif + return proc; +} + +bool +Console1::spill_plugins (const int32_t plugin_index) +{ + bool mapping_found = false; + + remove_plugin_operations (); + + std::shared_ptr proc = find_plugin (plugin_index); + if (!proc) + return false; int32_t n_controls = -1; DEBUG_TRACE (DEBUG::Console1, string_compose ("Found plugin %1\n", proc->name ())); @@ -226,34 +320,36 @@ Console1::spill_plugins (const uint32_t plugin_index) DEBUG_TRACE (DEBUG::Console1, string_compose ("Found plugin id %1\n", plugin->unique_id ())); + try { + ControllerButton* cb = get_button (ControllerID::MUTE); + boost::function plugin_mapping = [=] () -> void { cb->set_led_state (!plugin_insert->enabled ()); }; + cb->set_plugin_action ([=] (uint32_t val) { + plugin_insert->enable (val == 0); + DEBUG_TRACE (DEBUG::Console1, + string_compose ("ControllerButton Plugin parameter %1: %2 \n", n_controls, val)); + }); + + plugin_insert->ActiveChanged.connect ( + plugin_connections, MISSING_INVALIDATOR, boost::bind (plugin_mapping), this); + plugin_insert->ActiveChanged (); + } catch (ControlNotFoundException&) { + DEBUG_TRACE (DEBUG::Console1, string_compose ("No ControllerButton found %1\n", n_controls)); + } PluginMappingMap::iterator pmmit = pluginMappingMap.find (plugin->unique_id ()); mapping_found = (pmmit != pluginMappingMap.end ()); + if (!mapping_found) { + create_mapping (proc, plugin); + return true; + } + PluginMapping pluginMapping = pmmit->second; + DEBUG_TRACE (DEBUG::Console1, string_compose ("Plugin mapping found for id %1, name %2\n", pluginMapping.id, pluginMapping.name)); set p = proc->what_can_be_automated (); - try { - ControllerButton* cb = get_button (ControllerID::MUTE); - boost::function plugin_mapping = [=] () -> void { cb->set_led_state (plugin_insert->enabled ()); }; - cb->set_plugin_action ([=] (uint32_t val) { - plugin_insert->enable (val == 127); - DEBUG_TRACE (DEBUG::Console1, - string_compose ("ControllerButton Plugin parameter %1: %2 \n", n_controls, val)); - }); - - plugin_insert->ActiveChanged.connect ( - plugin_connections, MISSING_INVALIDATOR, boost::bind (plugin_mapping), this); - plugin_insert->ActiveChanged (); - } catch (ControlNotFoundException&) { - DEBUG_TRACE (DEBUG::Console1, string_compose ("No ControllerButton found %1\n", n_controls)); - } - - if( !mapping_found ) - return true; - for (set::iterator j = p.begin (); j != p.end (); ++j) { ++n_controls; std::string n = proc->describe_parameter (*j); @@ -276,11 +372,13 @@ Console1::spill_plugins (const uint32_t plugin_index) std::shared_ptr c = plugin_insert->automation_control (Evoral::Parameter (PluginAutomation, 0, n_controls)); if (c) { + PluginParameterMapping ppm = pluginMapping.parameters[n_controls]; bool swtch = false; if (parameterDescriptor.integer_step && parameterDescriptor.upper == 1) { swtch = true; + } else if (ppm.is_switch ){ + swtch = true; } - PluginParameterMapping ppm = pluginMapping.parameters[n_controls]; if (!swtch) { try { Encoder* e = get_encoder (ppm.controllerId); @@ -288,13 +386,15 @@ Console1::spill_plugins (const uint32_t plugin_index) [=] (bool b, PBD::Controllable::GroupControlDisposition d) -> void { double v = parameterDescriptor.to_interface (c->get_value (), true); e->set_value (v * 127); + DEBUG_TRACE (DEBUG::Console1, + string_compose ("<-Encoder Plugin parameter %1: %2 - %3\n", n_controls, v*127, v)); }; e->set_plugin_action ([=] (uint32_t val) { double v = val / 127.f; c->set_value (parameterDescriptor.from_interface (v, true), PBD::Controllable::GroupControlDisposition::UseGroup); DEBUG_TRACE (DEBUG::Console1, - string_compose ("Encoder Plugin parameter %1: %2 - %3\n", n_controls, val, v)); + string_compose ("->Encoder Plugin parameter %1: %2 - %3\n", n_controls, val, v)); }); c->Changed.connect ( plugin_connections, MISSING_INVALIDATOR, boost::bind (plugin_mapping, _1, _2), this); @@ -309,6 +409,8 @@ Console1::spill_plugins (const uint32_t plugin_index) boost::function plugin_mapping = [=] (bool b, PBD::Controllable::GroupControlDisposition d) -> void { cb->set_led_state (c->get_value ()); + DEBUG_TRACE (DEBUG::Console1, + string_compose ("<-ControllerButton Plugin parameter %1: %2 \n", n_controls, c->get_value())); }; cb->set_plugin_action ([=] (uint32_t val) { double v = val / 127.f; @@ -316,7 +418,7 @@ Console1::spill_plugins (const uint32_t plugin_index) PBD::Controllable::GroupControlDisposition::UseGroup); DEBUG_TRACE ( DEBUG::Console1, - string_compose ("ControllerButton Plugin parameter %1: %2 - %3\n", n_controls, val, v)); + string_compose ("->ControllerButton Plugin parameter %1: %2 - %3\n", n_controls, val, v)); }); c->Changed.connect ( @@ -333,9 +435,4 @@ Console1::spill_plugins (const uint32_t plugin_index) return true; } -void -Console1::map_p () -{ - DEBUG_TRACE (DEBUG::Console1, "Console1::map_p"); -} } \ No newline at end of file diff --git a/libs/surfaces/console1/console1.cc b/libs/surfaces/console1/console1.cc index 8ce7223673..8c9c1741fe 100644 --- a/libs/surfaces/console1/console1.cc +++ b/libs/surfaces/console1/console1.cc @@ -17,6 +17,9 @@ */ +#include +#include + #include #include @@ -63,16 +66,16 @@ Console1::~Console1 () tear_down_gui (); - for( const auto &[_, b] : buttons ){ + for (const auto& [_, b] : buttons) { delete b; } - for( const auto &[_, b] : encoders ){ + for (const auto& [_, b] : encoders) { delete b; } - for( const auto &[_, b] : meters ){ + for (const auto& [_, b] : meters) { delete b; } - for( const auto &[_, b] : multi_buttons ){ + for (const auto& [_, b] : multi_buttons) { delete b; } @@ -114,6 +117,9 @@ Console1::set_active (bool yn) } ControlProtocol::set_active (yn); + /* this needs to be done that early, otherwise we'll miss the call of the signal */ + session->SessionLoaded.connect ( + session_connections, MISSING_INVALIDATOR, boost::bind (&Console1::notify_session_loaded, this), this); DEBUG_TRACE (DEBUG::Console1, string_compose ("Console1::set_active done with yn: '%1'\n", yn)); @@ -176,9 +182,7 @@ Console1::begin_using_device () periodic_timer->attach (main_loop ()->get_context ()); DEBUG_TRACE (DEBUG::Console1, "************** begin_using_device() ********************\n"); - create_strip_invetory (); connect_internal_signals (); - map_shift (false); return 0; } @@ -233,6 +237,25 @@ Console1::connect_internal_signals () console1_connections, MISSING_INVALIDATOR, [] () { DEBUG_TRACE (DEBUG::Console1, "VerticalZoomOut\n"); }, this); } +void +Console1::notify_session_loaded () +{ + DEBUG_TRACE (DEBUG::Console1, "************** Session Loaded() ********************\n"); + create_strip_invetory (); + connect_internal_signals (); + if (session) { + DEBUG_TRACE (DEBUG::Console1, "session available\n"); + uint32_t i = 0; + while (!first_selected_stripable () && i < 10 ) { + DEBUG_TRACE (DEBUG::Console1, "no stripable selected\n"); + std::this_thread::sleep_for (std::chrono::milliseconds (1000)); + ++i; + } + if( i < 11) + stripable_selection_changed (); + } +} + void Console1::setup_controls () { @@ -762,7 +785,7 @@ Console1::set_current_stripable (std::shared_ptr r) } // ToDo: subscribe to the fader automation modes so we can light the LEDs - + map_shift (shift_state); map_stripable_state (); } diff --git a/libs/surfaces/console1/console1.h b/libs/surfaces/console1/console1.h index 5e0820edfb..f813ef7f3e 100644 --- a/libs/surfaces/console1/console1.h +++ b/libs/surfaces/console1/console1.h @@ -49,6 +49,7 @@ namespace ARDOUR { class AsyncMIDIPort; class Bundle; class Port; +class Processor; class Session; class MidiPort; } @@ -104,9 +105,6 @@ class Console1 : public MIDISurface std::string input_port_name () const override; std::string output_port_name () const override; - uint32_t load_mappings (); - bool load_mapping (FILE* fin); - /*XMLNode& get_state () const; int set_state (const XMLNode&, int version);*/ PBD::Signal0 ConnectionChange; @@ -273,6 +271,7 @@ class Console1 : public MIDISurface { "TRACK_GROUP", ControllerID::TRACK_GROUP } }; private: + std::string config_dir_name = "c1mappings"; /* GUI */ mutable C1GUI* gui; void build_gui (); @@ -288,7 +287,10 @@ class Console1 : public MIDISurface uint32_t current_bank = 0; uint32_t current_strippable_index = 0; - uint32_t current_plugin_index = 0; + int32_t current_plugin_index = -1; +#ifdef MIXBUS + int32_t selected_intern_plugin_index = -1; +#endif std::shared_ptr current_pan_control = nullptr; @@ -360,6 +362,7 @@ class Console1 : public MIDISurface /* */ void all_lights_out (); + void notify_session_loaded (); void notify_transport_state_changed () override; void notify_solo_active_changed (bool) override; @@ -557,6 +560,8 @@ class Console1 : public MIDISurface struct PluginParameterMapping { int paramIndex; + bool shift = false; + bool is_switch = false; std::string name; ControllerID controllerId; }; @@ -571,12 +576,19 @@ class Console1 : public MIDISurface }; /* plugin handling */ - bool spill_plugins (const uint32_t plugin_index); + bool ensure_config_dir (); + uint32_t load_mappings (); + bool load_mapping (XMLNode* fin); + void create_mapping (const std::shared_ptr proc, const std::shared_ptr plugin); + + bool spill_plugins (const int32_t plugin_index); /* plugin operations */ - bool select_plugin (const uint32_t plugin_index); + void remove_plugin_operations (); + std::shared_ptr find_plugin (const int32_t plugin_index); + bool select_plugin (const int32_t plugin_index); - bool map_select_plugin (const uint32_t plugin_index); + bool map_select_plugin (const int32_t plugin_index); using PluginMappingMap = std::map; PluginMappingMap pluginMappingMap;