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/event_loop.h"
26 #include "pbd/file_utils.h"
27 #include "pbd/error.h"
29 #include "control_protocol/control_protocol.h"
31 #include "ardour/debug.h"
32 #include "ardour/control_protocol_manager.h"
34 #include "ardour/search_paths.h"
35 #include "ardour/selection.h"
36 #include "ardour/session.h"
38 using namespace ARDOUR;
44 ControlProtocolManager* ControlProtocolManager::_instance = 0;
45 const string ControlProtocolManager::state_node_name = X_("ControlProtocols");
46 PBD::Signal1<void,StripableNotificationListPtr> ControlProtocolManager::StripableSelectionChanged;
48 ControlProtocolInfo::~ControlProtocolInfo ()
50 if (protocol && descriptor) {
51 descriptor->destroy (descriptor, protocol);
55 delete state; state = 0;
58 delete (Glib::Module*) descriptor->module;
63 ControlProtocolManager::ControlProtocolManager ()
67 ControlProtocolManager::~ControlProtocolManager()
69 Glib::Threads::RWLock::WriterLock lm (protocols_lock);
71 for (list<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
75 control_protocols.clear ();
78 for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
79 (*p)->protocol = 0; // protocol was already destroyed above.
83 control_protocol_info.clear();
87 ControlProtocolManager::set_session (Session* s)
89 SessionHandlePtr::set_session (s);
96 Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
98 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
99 if ((*i)->requested || (*i)->mandatory) {
100 (void) activate (**i);
105 CoreSelection::StripableAutomationControls sac;
106 _session->selection().get_stripables (sac);
109 StripableNotificationListPtr v (new StripableNotificationList);
110 for (CoreSelection::StripableAutomationControls::iterator i = sac.begin(); i != sac.end(); ++i) {
111 if ((*i).stripable) {
112 v->push_back (boost::weak_ptr<Stripable> ((*i).stripable));
116 StripableSelectionChanged (v); /* EMIT SIGNAL */
122 ControlProtocolManager::activate (ControlProtocolInfo& cpi)
126 cpi.requested = true;
128 if ((cp = instantiate (cpi)) == 0) {
132 /* we split the set_state() and set_active() operations so that
133 protocols that need state to configure themselves (e.g. "What device
134 is connected, or supposed to be connected?") can get it before
135 actually starting any interaction.
139 /* force this by tweaking the internals of the state
142 cp->set_state (*cpi.state, Stateful::loading_state_version);
144 /* guarantee a call to
145 set_state() whether we have
146 existing state or not
148 cp->set_state (XMLNode(""), Stateful::loading_state_version);
151 if (cp->set_active (true)) {
152 error << string_compose (_("Control protocol support for %1 failed to activate"), cpi.name) << endmsg;
153 teardown (cpi, false);
160 ControlProtocolManager::deactivate (ControlProtocolInfo& cpi)
162 cpi.requested = false;
163 return teardown (cpi, true);
167 ControlProtocolManager::session_going_away()
169 SessionHandlePtr::session_going_away ();
170 /* Session::destroy() will explicitly call drop_protocols() so we don't
171 * have to worry about that here.
176 ControlProtocolManager::drop_protocols ()
178 /* called explicitly by Session::destroy() so that we can clean up
179 * before the process cycle stops and ports vanish.
182 Glib::Threads::RWLock::WriterLock lm (protocols_lock);
184 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
188 control_protocols.clear ();
190 for (list<ControlProtocolInfo*>::iterator p = control_protocol_info.begin(); p != control_protocol_info.end(); ++p) {
191 // mark existing protocols as requested
192 // otherwise the ControlProtocol instances are not recreated in set_session
193 if ((*p)->protocol) {
194 (*p)->requested = true;
196 ProtocolStatusChange (*p); /* EMIT SIGNAL */
202 ControlProtocolManager::instantiate (ControlProtocolInfo& cpi)
204 /* CALLER MUST HOLD LOCK */
210 cpi.descriptor = get_descriptor (cpi.path);
212 DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("instantiating %1\n", cpi.name));
214 if (cpi.descriptor == 0) {
215 error << string_compose (_("control protocol name \"%1\" has no descriptor"), cpi.name) << endmsg;
219 DEBUG_TRACE (DEBUG::ControlProtocols, string_compose ("initializing %1\n", cpi.name));
221 if ((cpi.protocol = cpi.descriptor->initialize (cpi.descriptor, _session)) == 0) {
222 error << string_compose (_("control protocol name \"%1\" could not be initialized"), cpi.name) << endmsg;
226 control_protocols.push_back (cpi.protocol);
228 ProtocolStatusChange (&cpi);
234 ControlProtocolManager::teardown (ControlProtocolInfo& cpi, bool lock_required)
238 /* we could still have a descriptor even if the protocol was
239 never instantiated. Close the associated module (shared
240 object/DLL) and make sure we forget about it.
243 if (cpi.descriptor) {
244 cerr << "Closing descriptor for CPI anyway\n";
245 delete (Glib::Module*) cpi.descriptor->module;
252 if (!cpi.descriptor) {
260 /* save current state */
263 cpi.state = new XMLNode (cpi.protocol->get_state());
264 cpi.state->set_property (X_("active"), false);
266 cpi.descriptor->destroy (cpi.descriptor, cpi.protocol);
269 /* the lock is required when the protocol is torn down by a user from the GUI. */
270 Glib::Threads::RWLock::WriterLock lm (protocols_lock);
271 list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
272 if (p != control_protocols.end()) {
273 control_protocols.erase (p);
275 cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
278 list<ControlProtocol*>::iterator p = find (control_protocols.begin(), control_protocols.end(), cpi.protocol);
279 if (p != control_protocols.end()) {
280 control_protocols.erase (p);
282 cerr << "Programming error: ControlProtocolManager::teardown() called for " << cpi.name << ", but it was not found in control_protocols" << endl;
288 delete (Glib::Module*) cpi.descriptor->module;
289 /* cpi->descriptor is now inaccessible since dlclose() or equivalent
290 * has been performed, and the descriptor is (or could be) a static
291 * object made accessible by dlopen().
295 ProtocolStatusChange (&cpi);
301 ControlProtocolManager::load_mandatory_protocols ()
307 Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
309 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
310 if ((*i)->mandatory && ((*i)->protocol == 0)) {
311 DEBUG_TRACE (DEBUG::ControlProtocols,
312 string_compose (_("Instantiating mandatory control protocol %1"), (*i)->name));
319 ControlProtocolManager::discover_control_protocols ()
321 vector<std::string> cp_modules;
325 * Different build targets (Debug / Release etc) use different versions
326 * of the 'C' runtime (which can't be 'mixed & matched'). Therefore, in
327 * case the supplied search path contains multiple version(s) of a given
328 * module, only select the one(s) which match the current build target
331 Glib::PatternSpec dll_extension_pattern("*D.dll");
332 #elif defined (RDC_BUILD)
333 Glib::PatternSpec dll_extension_pattern("*RDC.dll");
334 #elif defined (_WIN64)
335 Glib::PatternSpec dll_extension_pattern("*64.dll");
337 Glib::PatternSpec dll_extension_pattern("*32.dll");
340 Glib::PatternSpec dll_extension_pattern("*.dll");
343 Glib::PatternSpec so_extension_pattern("*.so");
344 Glib::PatternSpec dylib_extension_pattern("*.dylib");
346 find_files_matching_pattern (cp_modules, control_protocol_search_path (),
347 dll_extension_pattern);
349 find_files_matching_pattern (cp_modules, control_protocol_search_path (),
350 so_extension_pattern);
352 find_files_matching_pattern (cp_modules, control_protocol_search_path (),
353 dylib_extension_pattern);
355 DEBUG_TRACE (DEBUG::ControlProtocols,
356 string_compose (_("looking for control protocols in %1\n"), control_protocol_search_path().to_string()));
358 for (vector<std::string>::iterator i = cp_modules.begin(); i != cp_modules.end(); ++i) {
359 control_protocol_discover (*i);
364 ControlProtocolManager::control_protocol_discover (string path)
366 ControlProtocolDescriptor* descriptor;
369 /* don't load OS X shared objects that are just symlinks to the real thing.
372 if (path.find (".dylib") && Glib::file_test (path, Glib::FILE_TEST_IS_SYMLINK)) {
377 if ((descriptor = get_descriptor (path)) != 0) {
379 if (!descriptor->probe (descriptor)) {
380 warning << string_compose (_("Control protocol %1 not usable"), descriptor->name) << endmsg;
383 ControlProtocolInfo* cpi = new ControlProtocolInfo ();
385 cpi->descriptor = descriptor;
386 cpi->name = descriptor->name;
389 cpi->requested = false;
390 cpi->mandatory = descriptor->mandatory;
391 cpi->supports_feedback = descriptor->supports_feedback;
394 control_protocol_info.push_back (cpi);
396 DEBUG_TRACE (DEBUG::ControlProtocols,
397 string_compose(_("Control surface protocol discovered: \"%1\"\n"), cpi->name));
404 ControlProtocolDescriptor*
405 ControlProtocolManager::get_descriptor (string path)
407 Glib::Module* module = new Glib::Module(path);
408 ControlProtocolDescriptor *descriptor = 0;
409 ControlProtocolDescriptor* (*dfunc)(void);
413 error << string_compose(_("ControlProtocolManager: cannot load module \"%1\" (%2)"), path, Glib::Module::get_last_error()) << endmsg;
418 if (!module->get_symbol("protocol_descriptor", func)) {
419 error << string_compose(_("ControlProtocolManager: module \"%1\" has no descriptor function."), path) << endmsg;
420 error << Glib::Module::get_last_error() << endmsg;
425 dfunc = (ControlProtocolDescriptor* (*)(void))func;
426 descriptor = dfunc();
429 descriptor->module = (void*)module;
436 ControlProtocolManager::foreach_known_protocol (boost::function<void(const ControlProtocolInfo*)> method)
438 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
444 ControlProtocolManager::cpi_by_name (string name)
446 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
447 if (name == (*i)->name) {
455 ControlProtocolManager::set_state (const XMLNode& node, int session_specific_state /* here: not version */)
458 XMLNodeConstIterator citer;
460 Glib::Threads::RWLock::WriterLock lm (protocols_lock);
462 clist = node.children();
464 for (citer = clist.begin(); citer != clist.end(); ++citer) {
465 XMLNode const * child = *citer;
467 if (child->name() == X_("Protocol")) {
471 if (!child->get_property (X_("active"), active) ||
472 !child->get_property (X_("name"), name)) {
476 ControlProtocolInfo* cpi = cpi_by_name (name);
480 std::cerr << "protocol " << name << " active ? " << active << std::endl;
485 cpi->state = new XMLNode (**citer);
486 cpi->state->set_property (X_("session-state"), session_specific_state ? true : false);
490 cpi->requested = true;
494 cpi->state = new XMLNode (**citer);
495 cpi->state->set_property (X_("active"), false);
496 cpi->state->set_property (X_("session-state"), session_specific_state ? true : false);
498 cpi->requested = false;
500 teardown (*cpi, false);
504 std::cerr << "protocol " << name << " not found\n";
513 ControlProtocolManager::get_state ()
515 XMLNode* root = new XMLNode (state_node_name);
516 Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
518 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
520 if ((*i)->protocol) {
521 XMLNode& child_state ((*i)->protocol->get_state());
522 child_state.set_property (X_("active"), true);
523 delete ((*i)->state);
524 (*i)->state = new XMLNode (child_state);
525 root->add_child_nocopy (child_state);
526 } else if ((*i)->state) {
527 XMLNode* child_state = new XMLNode (*(*i)->state);
528 child_state->set_property (X_("active"), false);
529 root->add_child_nocopy (*child_state);
531 XMLNode* child_state = new XMLNode (X_("Protocol"));
532 child_state->set_property (X_("name"), (*i)->name);
533 child_state->set_property (X_("active"), false);
534 root->add_child_nocopy (*child_state);
543 ControlProtocolManager&
544 ControlProtocolManager::instance ()
546 if (_instance == 0) {
547 _instance = new ControlProtocolManager ();
554 ControlProtocolManager::midi_connectivity_established ()
556 Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
558 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
559 (*p)->midi_connectivity_established ();
564 ControlProtocolManager::register_request_buffer_factories ()
566 Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
568 for (list<ControlProtocolInfo*>::iterator i = control_protocol_info.begin(); i != control_protocol_info.end(); ++i) {
570 if ((*i)->descriptor == 0) {
571 warning << string_compose (_("Control protocol \"%1\" has no descriptor"), (*i)->name) << endmsg;
575 if ((*i)->descriptor->request_buffer_factory) {
576 EventLoop::register_request_buffer_factory ((*i)->descriptor->name, (*i)->descriptor->request_buffer_factory);
582 ControlProtocolManager::stripable_selection_changed (StripableNotificationListPtr sp)
584 /* this sets up the (static) data structures owned by ControlProtocol
585 that are "shared" across all control protocols.
588 DEBUG_TRACE (DEBUG::Selection, string_compose ("Surface manager: selection changed, now %1 stripables\n", sp ? sp->size() : -1));
589 StripableSelectionChanged (sp); /* EMIT SIGNAL */
591 /* now give each protocol the chance to respond to the selection change
595 Glib::Threads::RWLock::ReaderLock lm (protocols_lock);
597 for (list<ControlProtocol*>::iterator p = control_protocols.begin(); p != control_protocols.end(); ++p) {
598 DEBUG_TRACE (DEBUG::Selection, string_compose ("selection change notification for surface \"%1\"\n", (*p)->name()));
599 (*p)->stripable_selection_changed ();