2 Copyright (C) 2002 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.
22 #include "pbd/debug.h"
25 #include "ardour/audioengine.h"
26 #include "ardour/midi_port.h"
27 #include "ardour/session.h"
28 #include "ardour/transport_master.h"
29 #include "ardour/transport_master_manager.h"
30 #include "ardour/types_convert.h"
31 #include "ardour/utils.h"
34 namespace Properties {
35 PBD::PropertyDescriptor<bool> fr2997;
36 PBD::PropertyDescriptor<bool> sclock_synced;
37 PBD::PropertyDescriptor<bool> collect;
38 PBD::PropertyDescriptor<bool> connected;
39 PBD::PropertyDescriptor<TransportRequestType> allowed_transport_requests;
43 using namespace ARDOUR;
47 TransportMaster::make_property_quarks ()
49 Properties::fr2997.property_id = g_quark_from_static_string (X_("fr2997"));
50 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for fr2997 = %1\n", Properties::fr2997.property_id));
51 Properties::sclock_synced.property_id = g_quark_from_static_string (X_("sclock_synced"));
52 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for sclock_synced = %1\n", Properties::sclock_synced.property_id));
53 Properties::collect.property_id = g_quark_from_static_string (X_("collect"));
54 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for collect = %1\n", Properties::collect.property_id));
55 Properties::connected.property_id = g_quark_from_static_string (X_("connected"));
56 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for connected = %1\n", Properties::connected.property_id));
57 Properties::allowed_transport_requests.property_id = g_quark_from_static_string (X_("allowed_transport_requests"));
58 DEBUG_TRACE (DEBUG::Properties, string_compose ("quark for allowed_transport_requests = %1\n", Properties::allowed_transport_requests.property_id));
61 const std::string TransportMaster::state_node_name = X_("TransportMaster");
63 TransportMaster::TransportMaster (SyncSource t, std::string const & name)
65 , _name (Properties::name, name)
68 , _pending_collect (true)
69 , _request_mask (Properties::allowed_transport_requests, TransportRequestType (0))
70 , _locked (Properties::locked, false)
71 , _sclock_synced (Properties::sclock_synced, false)
72 , _collect (Properties::collect, true)
73 , _connected (Properties::connected, false)
75 register_properties ();
77 ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect_same_thread (port_connection, boost::bind (&TransportMaster::connection_handler, this, _1, _2, _3, _4, _5));
78 ARDOUR::AudioEngine::instance()->Running.connect_same_thread (backend_connection, boost::bind (&TransportMaster::check_backend, this));
81 TransportMaster::~TransportMaster()
87 TransportMaster::register_properties ()
89 _xml_node_name = state_node_name;
92 add_property (_locked);
93 add_property (_collect);
94 add_property (_sclock_synced);
95 add_property (_request_mask);
97 /* we omit _connected since it is derived from port state, and merely
103 TransportMaster::set_name (std::string const & str)
107 PropertyChange (Properties::name);
112 TransportMaster::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
118 const std::string fqn = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->name());
120 if (fqn == name1 || fqn == name2) {
124 /* XXX technically .. if the user makes an N->1 connection to
125 * this transport master's port, this simple minded logic is
126 * not sufficient. But the user shouldn't do that ...
135 PropertyChanged (Properties::connected);
144 TransportMaster::check_collect()
150 /* XXX should probably use boost::atomic something or other here */
152 if (_pending_collect != _collect) {
153 if (_pending_collect) {
156 if (TransportMasterManager::instance().current().get() == this) {
158 _session->config.set_external_sync (false);
162 _collect = _pending_collect;
163 PropertyChanged (Properties::collect);
170 TransportMaster::set_collect (bool yn)
172 _pending_collect = yn;
176 TransportMaster::set_sample_clock_synced (bool yn)
178 if (yn != _sclock_synced) {
180 PropertyChanged (Properties::sclock_synced);
185 TransportMaster::set_session (Session* s)
191 TransportMaster::set_state (XMLNode const & node, int /* version */)
193 PropertyChange what_changed;
195 what_changed = set_values (node);
197 XMLNode* pnode = node.child (X_("Port"));
200 XMLNodeList const & children = pnode->children();
201 for (XMLNodeList::const_iterator ci = children.begin(); ci != children.end(); ++ci) {
203 XMLProperty const *prop;
205 if ((*ci)->name() == X_("Connection")) {
206 if ((prop = (*ci)->property (X_("other"))) == 0) {
209 _port->connect (prop->value());
214 PropertyChanged (what_changed);
220 TransportMaster::get_state ()
222 XMLNode* node = new XMLNode (state_node_name);
223 node->set_property (X_("type"), _type);
225 add_properties (*node);
228 std::vector<std::string> connections;
230 XMLNode* pnode = new XMLNode (X_("Port"));
232 if (_port->get_connections (connections)) {
234 std::vector<std::string>::const_iterator ci;
235 std::sort (connections.begin(), connections.end());
237 for (ci = connections.begin(); ci != connections.end(); ++ci) {
239 /* if its a connection to our own port,
240 return only the port name, not the
241 whole thing. this allows connections
242 to be re-established even when our
243 client name is different.
246 XMLNode* cnode = new XMLNode (X_("Connection"));
248 cnode->set_property (X_("other"), AudioEngine::instance()->make_port_name_relative (*ci));
249 pnode->add_child_nocopy (*cnode);
253 node->add_child_nocopy (*pnode);
259 boost::shared_ptr<TransportMaster>
260 TransportMaster::factory (XMLNode const & node)
262 if (node.name() != TransportMaster::state_node_name) {
263 return boost::shared_ptr<TransportMaster>();
269 if (!node.get_property (X_("type"), type)) {
270 return boost::shared_ptr<TransportMaster>();
273 if (!node.get_property (X_("name"), name)) {
274 return boost::shared_ptr<TransportMaster>();
277 return factory (type, name);
280 boost::shared_ptr<TransportMaster>
281 TransportMaster::factory (SyncSource type, std::string const& name)
283 /* XXX need to count existing sources of a given type */
287 return boost::shared_ptr<TransportMaster> (new MTC_TransportMaster (sync_source_to_string (type)));
289 return boost::shared_ptr<TransportMaster> (new LTC_TransportMaster (sync_source_to_string (type)));
291 return boost::shared_ptr<TransportMaster> (new MIDIClock_TransportMaster (sync_source_to_string (type)));
293 return boost::shared_ptr<TransportMaster> (new Engine_TransportMaster (*AudioEngine::instance()));
298 return boost::shared_ptr<TransportMaster>();
301 boost::shared_ptr<Port>
302 TransportMasterViaMIDI::create_midi_port (std::string const & port_name)
304 boost::shared_ptr<Port> p;
306 if ((p = AudioEngine::instance()->register_input_port (DataType::MIDI, port_name)) == 0) {
307 return boost::shared_ptr<Port> ();
310 _midi_port = boost::dynamic_pointer_cast<MidiPort> (p);
316 TransportMaster::allow_request (TransportRequestSource src, TransportRequestType type) const
318 return _request_mask & type;
322 TransportMaster::set_request_mask (TransportRequestType t)
324 if (_request_mask != t) {
326 PropertyChanged (Properties::allowed_transport_requests);
330 TimecodeTransportMaster::TimecodeTransportMaster (std::string const & name, SyncSource type)
331 : TransportMaster (type, name)
332 , _fr2997 (Properties::fr2997, false)
334 register_properties ();
338 TimecodeTransportMaster::register_properties ()
340 TransportMaster::register_properties ();
341 add_property (_fr2997);
345 TimecodeTransportMaster::set_fr2997 (bool yn)
349 PropertyChanged (Properties::fr2997);