major redesign of MIDI port heirarchy and management (part 2)
[ardour.git] / libs / ardour / port.cc
1 /*
2     Copyright (C) 2009 Paul Davis
3
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.
8
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.
13
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.
17
18 */
19
20 #ifdef WAF_BUILD
21 #include "libardour-config.h"
22 #endif
23
24 #include <jack/weakjack.h> // so that we can test for new functions at runtime
25
26 #include "pbd/compose.h"
27 #include "pbd/error.h"
28 #include "pbd/failed_constructor.h"
29
30 #include "ardour/audioengine.h"
31 #include "ardour/debug.h"
32 #include "ardour/port.h"
33 #include "ardour/port_engine.h"
34
35 #include "i18n.h"
36
37 using namespace std;
38 using namespace ARDOUR;
39 using namespace PBD;
40
41 PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect;
42 PBD::Signal0<void> Port::PortDrop;
43
44 bool         Port::_connecting_blocked = false;
45 pframes_t    Port::_global_port_buffer_offset = 0;
46 pframes_t    Port::_cycle_nframes = 0;
47
48 /* a handy define to shorten what would otherwise be a needlessly verbose
49  * repeated phrase
50  */
51 #define port_engine AudioEngine::instance()->port_engine()
52 #define port_manager AudioEngine::instance()
53
54 /** @param n Port short name */
55 Port::Port (std::string const & n, DataType t, PortFlags f)
56         : _port_buffer_offset (0)
57         , _name (n)
58         , _flags (f)
59         , _last_monitor (false)
60 {
61         _private_playback_latency.min = 0;
62         _private_playback_latency.max = 0;
63         _private_capture_latency.min = 0;
64         _private_capture_latency.max = 0;
65
66         /* Unfortunately we have to pass the DataType into this constructor so that
67            we can create the right kind of port; aside from this we'll use the
68            virtual function type () to establish type.
69         */
70
71         assert (_name.find_first_of (':') == std::string::npos);
72
73         if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) {
74                 cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n";
75                 throw failed_constructor ();
76         }
77         
78         PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this));
79 }
80
81 /** Port destructor */
82 Port::~Port ()
83 {
84         drop ();
85 }
86
87 void
88 Port::drop ()
89 {
90         if (_port_handle) {
91                 port_engine.unregister_port (_port_handle);
92                 _port_handle = 0;
93         }
94 }
95
96 /** @return true if this port is connected to anything */
97 bool
98 Port::connected () const
99 {
100         return (port_engine.connected (_port_handle) != 0);
101 }
102
103 int
104 Port::disconnect_all ()
105 {
106         port_engine.disconnect_all (_port_handle);
107         _connections.clear ();
108
109         /* a cheaper, less hacky way to do boost::shared_from_this() ... 
110          */
111         boost::shared_ptr<Port> pself = port_manager->get_port_by_name (name());
112         PostDisconnect (pself, boost::shared_ptr<Port>()); // emit signal
113
114         return 0;
115 }
116
117 /** @param o Port name
118  * @return true if this port is connected to o, otherwise false.
119  */
120 bool
121 Port::connected_to (std::string const & o) const
122 {
123         return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o));
124 }
125
126 int
127 Port::get_connections (std::vector<std::string> & c) const
128 {
129         return port_engine.get_connections (_port_handle, c);
130 }
131
132 int
133 Port::connect (std::string const & other)
134 {
135         std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other);
136         std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name);
137
138         int r = 0;
139
140         if (_connecting_blocked) {
141                 return r;
142         }
143
144         if (sends_output ()) {
145                 port_engine.connect (our_name, other_name);
146         } else {
147                 port_engine.connect (other_name, our_name);
148         }
149
150         if (r == 0) {
151                 _connections.insert (other);
152         }
153
154         return r;
155 }
156
157 int
158 Port::disconnect (std::string const & other)
159 {
160         std::string const other_fullname = port_manager->make_port_name_non_relative (other);
161         std::string const this_fullname = port_manager->make_port_name_non_relative (_name);
162
163         int r = 0;
164
165         if (sends_output ()) {
166                 r = port_engine.disconnect (this_fullname, other_fullname);
167         } else {
168                 r = port_engine.disconnect (other_fullname, this_fullname);
169         }
170
171         if (r == 0) {
172                 _connections.erase (other);
173         }
174
175         /* a cheaper, less hacky way to do boost::shared_from_this() ... 
176          */
177         boost::shared_ptr<Port> pself = AudioEngine::instance()->get_port_by_name (name());
178         boost::shared_ptr<Port> pother = AudioEngine::instance()->get_port_by_name (other);
179
180         if (pself && pother) {
181                 /* Disconnecting from another Ardour port: need to allow
182                    a check on whether this may affect anything that we
183                    need to know about.
184                 */
185                 PostDisconnect (pself, pother); // emit signal 
186         }
187
188         return r;
189 }
190
191
192 bool
193 Port::connected_to (Port* o) const
194 {
195         return connected_to (o->name ());
196 }
197
198 int
199 Port::connect (Port* o)
200 {
201         return connect (o->name ());
202 }
203
204 int
205 Port::disconnect (Port* o)
206 {
207         return disconnect (o->name ());
208 }
209
210 void
211 Port::request_input_monitoring (bool yn)
212 {
213         port_engine.request_input_monitoring (_port_handle, yn);
214 }
215
216 void
217 Port::ensure_input_monitoring (bool yn)
218 {
219         port_engine.ensure_input_monitoring (_port_handle, yn);
220 }
221
222 bool
223 Port::monitoring_input () const
224 {
225         
226         return port_engine.monitoring_input (_port_handle);
227 }
228
229 void
230 Port::reset ()
231 {
232         _last_monitor = false;
233 }
234
235 void
236 Port::cycle_start (pframes_t)
237 {
238         _port_buffer_offset = 0;
239 }
240
241 void
242 Port::increment_port_buffer_offset (pframes_t nframes)
243 {
244         _port_buffer_offset += nframes;
245 }
246
247 void
248 Port::set_public_latency_range (LatencyRange& range, bool playback) const
249 {
250         /* this sets the visible latency that the rest of the port system
251            sees. because we do latency compensation, all (most) of our visible
252            port latency values are identical.
253         */
254
255         DEBUG_TRACE (DEBUG::Latency,
256                      string_compose ("SET PORT %1 %4 PUBLIC latency now [%2 - %3]\n",
257                                      name(), range.min, range.max,
258                                      (playback ? "PLAYBACK" : "CAPTURE")));;
259
260         port_engine.set_latency_range (_port_handle, playback, range);
261 }
262
263 void
264 Port::set_private_latency_range (LatencyRange& range, bool playback)
265 {
266         if (playback) {
267                 _private_playback_latency = range;
268                 DEBUG_TRACE (DEBUG::Latency, string_compose (
269                                      "SET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
270                                      name(),
271                                      _private_playback_latency.min,
272                                      _private_playback_latency.max));
273         } else {
274                 _private_capture_latency = range;
275                 DEBUG_TRACE (DEBUG::Latency, string_compose (
276                                      "SET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
277                                      name(),
278                                      _private_capture_latency.min,
279                                      _private_capture_latency.max));
280         }
281
282         /* push to public (port system) location so that everyone else can see it */
283
284         set_public_latency_range (range, playback);
285 }
286
287 const LatencyRange&
288 Port::private_latency_range (bool playback) const
289 {
290         if (playback) {
291                 DEBUG_TRACE (DEBUG::Latency, string_compose (
292                                      "GET PORT %1 playback PRIVATE latency now [%2 - %3]\n",
293                                      name(),
294                                      _private_playback_latency.min,
295                                      _private_playback_latency.max));
296                 return _private_playback_latency;
297         } else {
298                 DEBUG_TRACE (DEBUG::Latency, string_compose (
299                                      "GET PORT %1 capture PRIVATE latency now [%2 - %3]\n",
300                                      name(),
301                                      _private_playback_latency.min,
302                                      _private_playback_latency.max));
303                 return _private_capture_latency;
304         }
305 }
306
307 LatencyRange
308 Port::public_latency_range (bool /*playback*/) const
309 {
310         LatencyRange r;
311
312         r = port_engine.get_latency_range (_port_handle, sends_output() ? true : false);
313
314         DEBUG_TRACE (DEBUG::Latency, string_compose (
315                              "GET PORT %1: %4 PUBLIC latency range %2 .. %3\n",
316                              name(), r.min, r.max,
317                              sends_output() ? "PLAYBACK" : "CAPTURE"));
318         return r;
319 }
320
321 void
322 Port::get_connected_latency_range (LatencyRange& range, bool playback) const
323 {
324         vector<string> connections;
325
326         get_connections (connections);
327
328         if (!connections.empty()) {
329
330                 range.min = ~((jack_nframes_t) 0);
331                 range.max = 0;
332
333                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: %2 connections to check for latency range\n", name(), connections.size()));
334
335                 for (vector<string>::const_iterator c = connections.begin();
336                      c != connections.end(); ++c) {
337
338                         LatencyRange lr;
339
340                         if (!AudioEngine::instance()->port_is_mine (*c)) {
341
342                                 /* port belongs to some other port-system client, use
343                                  * the port engine to lookup its latency information.
344                                  */
345
346                                 PortEngine::PortHandle remote_port = port_engine.get_port_by_name (*c);
347
348                                 if (remote_port) {
349                                         lr = port_engine.get_latency_range (remote_port, playback);
350
351                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
352                                                              "\t%1 <-> %2 : latter has latency range %3 .. %4\n",
353                                                              name(), *c, lr.min, lr.max));
354
355                                         range.min = min (range.min, lr.min);
356                                         range.max = max (range.max, lr.max);
357                                 }
358
359                         } else {
360
361                                 /* port belongs to this instance of ardour,
362                                    so look up its latency information
363                                    internally, because our published/public
364                                    values already contain our plugin
365                                    latency compensation.
366                                 */
367
368                                 boost::shared_ptr<Port> remote_port = AudioEngine::instance()->get_port_by_name (*c);
369                                 if (remote_port) {
370                                         lr = remote_port->private_latency_range ((playback ? JackPlaybackLatency : JackCaptureLatency));
371                                         DEBUG_TRACE (DEBUG::Latency, string_compose (
372                                                              "\t%1 <-LOCAL-> %2 : latter has latency range %3 .. %4\n",
373                                                              name(), *c, lr.min, lr.max));
374
375                                         range.min = min (range.min, lr.min);
376                                         range.max = max (range.max, lr.max);
377                                 }
378                         }
379                 }
380
381         } else {
382                 DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: not connected to anything\n", name()));
383                 range.min = 0;
384                 range.max = 0;
385         }
386
387         DEBUG_TRACE (DEBUG::Latency, string_compose ("%1: final connected latency range [ %2 .. %3 ] \n", name(), range.min, range.max));
388 }
389
390 int
391 Port::reestablish ()
392 {
393         DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name));
394         _port_handle = port_engine.register_port (_name, type(), _flags);
395
396         if (_port_handle == 0) {
397                 PBD::error << string_compose (_("could not reregister %1"), _name) << endmsg;
398                 return -1;
399         }
400
401         reset ();
402
403         return 0;
404 }
405
406
407 int
408 Port::reconnect ()
409 {
410         /* caller must hold process lock; intended to be used only after reestablish() */
411
412         for (std::set<string>::iterator i = _connections.begin(); i != _connections.end(); ++i) {
413                 if (connect (*i)) {
414                         return -1;
415                 }
416         }
417
418         return 0;
419 }
420
421 /** @param n Short port name (no port-system client name) */
422 int
423 Port::set_name (std::string const & n)
424 {
425         if (n == _name) {
426                 return 0;
427         }
428
429         int const r = port_engine.set_port_name (_port_handle, n);
430
431         if (r == 0) {
432                 AudioEngine::instance()->port_renamed (_name, n);
433                 _name = n;
434         }
435
436
437         return r;
438 }
439
440 bool
441 Port::physically_connected () const
442 {
443         return port_engine.physically_connected (_port_handle);
444 }
445