2 Copyright (C) 2000-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #include <glibmm/module.h>
22 #include <glibmm/fileutils.h>
24 #include "pbd/compose.h"
25 #include "pbd/file_utils.h"
26 #include "pbd/error.h"
28 #include "control_protocol/control_protocol.h"
30 #include "ardour/debug.h"
31 #include "ardour/control_protocol_manager.h"
33 #include "ardour/search_paths.h"
36 using namespace ARDOUR;
42 ControlProtocolManager* ControlProtocolManager::_instance = 0;
43 const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
45 ControlProtocolManager::ControlProtocolManager ()
49 ControlProtocolManager::~ControlProtocolManager()
51 Glib::Threads::Mutex::Lock lm (protocols_lock);
53 for (list<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
57 control_protocols.clear ();
60 for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
64 control_protocol_info.clear();
68 ControlProtocolManager::set_session (Session* s)
70 SessionHandlePtr::set_session (s);
73 Glib::Threads::Mutex::Lock lm (protocols_lock);
75 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
76 if ((*i)->requested || (*i)->mandatory) {
77 (void) activate (**i);
84 ControlProtocolManager::activate (ControlProtocolInfo& cpi)
90 if ((cp = instantiate (cpi)) == 0) {
94 /* we split the set_state() and set_active() operations so that
95 protocols that need state to configure themselves (e.g. "What device
96 is connected, or supposed to be connected?") can get it before
97 actually starting any interaction.
101 /* force this by tweaking the internals of the state
104 cp->set_state (*cpi.state, Stateful::loading_state_version);
106 /* guarantee a call to
107 set_state() whether we have
108 existing state or not
110 cp->set_state (XMLNode(""), Stateful::loading_state_version);
113 cp->set_active (true);
119 ControlProtocolManager::deactivate (ControlProtocolInfo& cpi)
121 cpi.requested = false;
122 return teardown (cpi);
126 ControlProtocolManager::session_going_away()
128 SessionHandlePtr::session_going_away ();
131 Glib::Threads::Mutex::Lock lm (protocols_lock);
133 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
137 control_protocols.clear ();
139 for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
140 // mark existing protocols as requested
141 // otherwise the ControlProtocol instances are not recreated in set_session
142 if ((*p)->protocol) {
143 (*p)->requested = true;
151 ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
153 /* CALLER MUST HOLD LOCK */
159 cpi.descriptor = get_descriptor (cpi.path);
161 DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("instantiating %1\n", cpi.name));
163 if (cpi.descriptor == 0) {
164 error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
168 DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("initializing %1\n", cpi.name));
170 if ((cpi.protocol = cpi.descriptor->initialize (cpi.descriptor, _session)) == 0) {
171 error << string_compose (_("control protocol name \"%1\" could not be initialized"), cpi.name) << endmsg;
175 control_protocols.push_back (cpi.protocol);
177 ProtocolStatusChange (&cpi);
183 ControlProtocolManager::teardown (ControlProtocolInfo& cpi)
189 if (!cpi.descriptor) {
197 /* save current state */
200 cpi.state = new XMLNode (cpi.protocol->get_state());
201 cpi.state->add_property (X_("active"), "no");
203 cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
206 Glib::Threads::Mutex::Lock lm (protocols_lock);
207 list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
208 if (p != control_protocols.end()) {
209 control_protocols.erase (p);
211 cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
218 delete (Glib::Module*)cpi.descriptor->module;
220 ProtocolStatusChange (&cpi);
226 ControlProtocolManager::load_mandatory_protocols ()
232 Glib::Threads::Mutex::Lock lm (protocols_lock);
234 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
235 if ((*i)->mandatory && ((*i)->protocol == 0)) {
236 DEBUG_TRACE (DEBUG::ControlProtocols,
237 string_compose (_("Instantiating mandatory control protocol %1"), (*i)->name));
244 ControlProtocolManager::discover_control_protocols ()
246 vector<std::string> cp_modules;
250 * Different build targets (Debug / Release etc) use different versions
251 * of the 'C' runtime (which can't be 'mixed & matched'). Therefore, in
252 * case the supplied search path contains multiple version(s) of a given
253 * module, only select the one(s) which match the current build target
256 Glib::PatternSpec dll_extension_pattern("*D.dll");
257 #elif defined (RDC_BUILD)
258 Glib::PatternSpec dll_extension_pattern("*RDC.dll");
259 #elif defined (_WIN64)
260 Glib::PatternSpec dll_extension_pattern("*64.dll");
262 Glib::PatternSpec dll_extension_pattern("*32.dll");
265 Glib::PatternSpec dll_extension_pattern("*.dll");
268 Glib::PatternSpec so_extension_pattern("*.so");
269 Glib::PatternSpec dylib_extension_pattern("*.dylib");
271 find_matching_files_in_search_path (control_protocol_search_path (),
272 dll_extension_pattern, cp_modules);
274 find_matching_files_in_search_path (control_protocol_search_path (),
275 so_extension_pattern, cp_modules);
277 find_matching_files_in_search_path (control_protocol_search_path (),
278 dylib_extension_pattern, cp_modules);
280 DEBUG_TRACE (DEBUG::ControlProtocols,
281 string_compose (_("looking for control protocols in %1\n"), control_protocol_search_path().to_string()));
283 for (vector<std::string>::iterator i = cp_modules.begin(); i != cp_modules.end(); ++i) {
284 control_protocol_discover (*i);
289 ControlProtocolManager::control_protocol_discover (string path)
291 ControlProtocolDescriptor* descriptor;
294 /* don't load OS X shared objects that are just symlinks to the real thing.
297 if (path.find (".dylib") && Glib::file_test (path, Glib::FILE_TEST_IS_SYMLINK)) {
302 if ((descriptor = get_descriptor (path)) != 0) {
304 if (!descriptor->probe (descriptor)) {
305 DEBUG_TRACE (DEBUG::ControlProtocols,
306 string_compose (_("Control protocol %1 not usable"), descriptor->name));
309 ControlProtocolInfo* cpi = new ControlProtocolInfo ();
311 cpi->descriptor = descriptor;
312 cpi->name = descriptor->name;
315 cpi->requested = false;
316 cpi->mandatory = descriptor->mandatory;
317 cpi->supports_feedback = descriptor->supports_feedback;
320 control_protocol_info.push_back (cpi);
322 DEBUG_TRACE (DEBUG::ControlProtocols,
323 string_compose(_("Control surface protocol discovered: \"%1\"\n"), cpi->name));
326 delete (Glib::Module*)descriptor->module;
332 ControlProtocolDescriptor*
333 ControlProtocolManager::get_descriptor (string path)
335 Glib::Module* module = new Glib::Module(path);
336 ControlProtocolDescriptor *descriptor = 0;
337 ControlProtocolDescriptor* (*dfunc)(void);
341 error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, Glib::Module::get_last_error()) << endmsg;
346 if (!module->get_symbol("protocol_descriptor", func)) {
347 error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
348 error << Glib::Module::get_last_error() << endmsg;
353 dfunc = (ControlProtocolDescriptor* (*)(void))func;
354 descriptor = dfunc();
357 descriptor->module = (void*)module;
366 ControlProtocolManager::foreach_known_protocol (boost::function<void(const ControlProtocolInfo*)> method)
368 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
374 ControlProtocolManager::cpi_by_name (string name)
376 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
377 if (name == (*i)->name) {
385 ControlProtocolManager::set_state (const XMLNode& node, int /*version*/)
388 XMLNodeConstIterator citer;
391 Glib::Threads::Mutex::Lock lm (protocols_lock);
393 clist = node.children();
395 for (citer = clist.begin(); citer != clist.end(); ++citer) {
396 if ((*citer)->name() == X_("Protocol")) {
398 if ((prop = (*citer)->property (X_("active"))) == 0) {
402 bool active = string_is_affirmative (prop->value());
404 if ((prop = (*citer)->property (X_("name"))) == 0) {
408 ControlProtocolInfo* cpi = cpi_by_name (prop->value());
411 cpi->state = new XMLNode (**citer);
417 cpi->requested = true;
423 cpi->requested = false;
434 ControlProtocolManager::get_state ()
436 XMLNode* root = new XMLNode (state_node_name);
437 Glib::Threads::Mutex::Lock lm (protocols_lock);
439 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
441 if ((*i)->protocol) {
442 XMLNode& child_state ((*i)->protocol->get_state());
443 child_state.add_property (X_("active"), "yes");
444 root->add_child_nocopy (child_state);
445 } else if ((*i)->state) {
446 XMLNode* child_state = new XMLNode (*(*i)->state);
447 child_state->add_property (X_("active"), "no");
448 root->add_child_nocopy (*child_state);
450 XMLNode* child_state = new XMLNode (X_("Protocol"));
451 child_state->add_property (X_("name"), (*i)->name);
452 child_state->add_property (X_("active"), "no");
453 root->add_child_nocopy (*child_state);
462 ControlProtocolManager&
463 ControlProtocolManager::instance ()
465 if (_instance == 0) {
466 _instance = new ControlProtocolManager ();
473 ControlProtocolManager::midi_connectivity_established ()
475 Glib::Threads::Mutex::Lock lm (protocols_lock);
477 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
478 (*p)->midi_connectivity_established ();