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.
24 #include "ardour/audioengine.h"
25 #include "ardour/midi_port.h"
26 #include "ardour/session.h"
27 #include "ardour/transport_master.h"
28 #include "ardour/transport_master_manager.h"
29 #include "ardour/utils.h"
31 using namespace ARDOUR;
33 const std::string TransportMaster::state_node_name = X_("TransportMaster");
36 TransportMaster::TransportMaster (SyncSource t, std::string const & name)
43 , _pending_collect (true)
44 , _request_mask (TransportRequestType (0))
45 , _sclock_synced (false)
47 ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect_same_thread (port_connection, boost::bind (&TransportMaster::connection_handler, this, _1, _2, _3, _4, _5));
48 ARDOUR::AudioEngine::instance()->Running.connect_same_thread (backend_connection, boost::bind (&TransportMaster::check_backend, this));
51 TransportMaster::~TransportMaster()
57 TransportMaster::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
63 const std::string fqn = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->name());
65 if (fqn == name1 || fqn == name2) {
82 TransportMaster::check_collect()
88 /* XXX should probably use boost::atomic something or other here */
90 if (_pending_collect != _collect) {
91 if (_pending_collect) {
94 if (TransportMasterManager::instance().current().get() == this) {
96 _session->config.set_external_sync (false);
100 std::cerr << name() << " pc = " << _pending_collect << " c = " << _collect << std::endl;
101 _collect = _pending_collect;
108 TransportMaster::set_collect (bool yn)
110 _pending_collect = yn;
114 TransportMaster::set_sample_clock_synced (bool yn)
120 TransportMaster::set_session (Session* s)
126 TransportMaster::set_state (XMLNode const & node, int /* version */)
128 if (!node.get_property (X_("collect"), _collect)) {
132 if (!node.get_property (X_("clock-synced"), _sclock_synced)) {
133 _sclock_synced = false;
136 TimecodeTransportMaster* ttm = dynamic_cast<TimecodeTransportMaster*> (this);
139 node.get_property (X_("fr2997"), val);
140 ttm->set_fr2997 (val);
143 XMLNode* pnode = node.child (X_("Port"));
146 XMLNodeList const & children = pnode->children();
147 for (XMLNodeList::const_iterator ci = children.begin(); ci != children.end(); ++ci) {
149 XMLProperty const *prop;
151 if ((*ci)->name() == X_("Connection")) {
152 if ((prop = (*ci)->property (X_("other"))) == 0) {
155 _port->connect (prop->value());
164 TransportMaster::get_state ()
166 XMLNode* node = new XMLNode (state_node_name);
167 node->set_property (X_("type"), _type);
168 node->set_property (X_("name"), _name);
169 node->set_property (X_("collect"), _collect);
170 node->set_property (X_("clock-synced"), _sclock_synced);
172 TimecodeTransportMaster* ttm = dynamic_cast<TimecodeTransportMaster*> (this);
174 node->set_property (X_("fr2997"), ttm->fr2997());
178 std::vector<std::string> connections;
180 XMLNode* pnode = new XMLNode (X_("Port"));
182 if (_port->get_connections (connections)) {
184 std::vector<std::string>::const_iterator ci;
185 std::sort (connections.begin(), connections.end());
187 for (ci = connections.begin(); ci != connections.end(); ++ci) {
189 /* if its a connection to our own port,
190 return only the port name, not the
191 whole thing. this allows connections
192 to be re-established even when our
193 client name is different.
196 XMLNode* cnode = new XMLNode (X_("Connection"));
198 cnode->set_property (X_("other"), AudioEngine::instance()->make_port_name_relative (*ci));
199 pnode->add_child_nocopy (*cnode);
203 node->add_child_nocopy (*pnode);
209 boost::shared_ptr<TransportMaster>
210 TransportMaster::factory (XMLNode const & node)
212 if (node.name() != TransportMaster::state_node_name) {
213 return boost::shared_ptr<TransportMaster>();
219 if (!node.get_property (X_("type"), type)) {
220 return boost::shared_ptr<TransportMaster>();
223 if (!node.get_property (X_("name"), name)) {
224 return boost::shared_ptr<TransportMaster>();
227 return factory (type, name);
230 boost::shared_ptr<TransportMaster>
231 TransportMaster::factory (SyncSource type, std::string const& name)
233 /* XXX need to count existing sources of a given type */
237 return boost::shared_ptr<TransportMaster> (new MTC_TransportMaster (sync_source_to_string (type)));
239 return boost::shared_ptr<TransportMaster> (new LTC_TransportMaster (sync_source_to_string (type)));
241 return boost::shared_ptr<TransportMaster> (new MIDIClock_TransportMaster (sync_source_to_string (type)));
243 return boost::shared_ptr<TransportMaster> (new Engine_TransportMaster (*AudioEngine::instance()));
248 return boost::shared_ptr<TransportMaster>();
251 boost::shared_ptr<Port>
252 TransportMasterViaMIDI::create_midi_port (std::string const & port_name)
254 boost::shared_ptr<Port> p;
256 if ((p = AudioEngine::instance()->register_input_port (DataType::MIDI, port_name)) == 0) {
257 return boost::shared_ptr<Port> ();
260 _midi_port = boost::dynamic_pointer_cast<MidiPort> (p);
266 TransportMaster::allow_request (TransportRequestSource src, TransportRequestType type) const
268 return _request_mask & type;
272 TransportMaster::set_request_mask (TransportRequestType t)
278 TimecodeTransportMaster::set_fr2997 (bool yn)