more miscellaneous changes for audioengine, all of this is still far from actually...
[ardour.git] / libs / ardour / audioengine.cc
1 /*
2     Copyright (C) 2002 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 #include <unistd.h>
21 #include <cerrno>
22 #include <vector>
23 #include <exception>
24 #include <stdexcept>
25 #include <sstream>
26
27 #include <glibmm/timer.h>
28
29 #include "pbd/pthread_utils.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/unknown_type.h"
32 #include "pbd/epa.h"
33
34 #include <jack/weakjack.h>
35
36 #include "midi++/port.h"
37 #include "midi++/jack_midi_port.h"
38 #include "midi++/mmc.h"
39 #include "midi++/manager.h"
40
41 #include "ardour/audio_port.h"
42 #include "ardour/audioengine.h"
43 #include "ardour/buffer.h"
44 #include "ardour/cycle_timer.h"
45 #include "ardour/internal_send.h"
46 #include "ardour/meter.h"
47 #include "ardour/midi_port.h"
48 #include "ardour/port.h"
49 #include "ardour/process_thread.h"
50 #include "ardour/session.h"
51
52 #include "i18n.h"
53
54 using namespace std;
55 using namespace ARDOUR;
56 using namespace PBD;
57
58 gint AudioEngine::m_meter_exit;
59 AudioEngine* AudioEngine::_instance = 0;
60
61 AudioEngine::AudioEngine ()
62         : session_remove_pending (false)
63         , session_removal_countdown (-1)
64         , monitor_check_interval (INT32_MAX)
65         , last_monitor_check (0)
66         , _processed_frames (0)
67         , _freewheeling (false)
68         , _pre_freewheel_mmc_enabled (false)
69         , _usecs_per_cycle (0)
70         , port_remove_in_progress (false)
71         , m_meter_thread (0)
72         , _main_thread (0)
73 {
74         g_atomic_int_set (&m_meter_exit, 0);
75
76         Port::set_engine (this);
77 }
78
79 AudioEngine::~AudioEngine ()
80 {
81         config_connection.disconnect ();
82
83         {
84                 Glib::Threads::Mutex::Lock tm (_process_lock);
85                 session_removed.signal ();
86                 stop_metering_thread ();
87         }
88 }
89
90 AudioEngine*
91 AudioEngine::create ()
92 {
93         if (_instance) {
94                 return _instance;
95         }
96         return new AudioEngine;
97 }
98
99 jack_client_t*
100 AudioEngine::jack() const
101 {
102         return _jack;
103 }
104
105 void
106 _thread_init_callback (void * /*arg*/)
107 {
108         /* make sure that anybody who needs to know about this thread
109            knows about it.
110         */
111
112         pthread_set_name (X_("audioengine"));
113
114         PBD::notify_gui_about_thread_creation ("gui", pthread_self(), X_("Audioengine"), 4096);
115         PBD::notify_gui_about_thread_creation ("midiui", pthread_self(), X_("Audioengine"), 128);
116
117         SessionEvent::create_per_thread_pool (X_("Audioengine"), 512);
118
119         MIDI::JackMIDIPort::set_process_thread (pthread_self());
120 }
121
122
123 int
124 AudioEngine::start ()
125 {
126         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
127
128         if (!_running) {
129
130                 if (!jack_port_type_get_buffer_size) {
131                         warning << _("This version of JACK is old - you should upgrade to a newer version that supports jack_port_type_get_buffer_size()") << endmsg;
132                 }
133
134                 if (_session) {
135                         BootMessage (_("Connect session to engine"));
136                         _session->set_frame_rate (jack_get_sample_rate (_priv_jack));
137                 }
138
139                 /* a proxy for whether jack_activate() will definitely call the buffer size
140                  * callback. with older versions of JACK, this function symbol will be null.
141                  * this is reliable, but not clean.
142                  */
143
144                 if (!jack_port_type_get_buffer_size) {
145                         jack_bufsize_callback (jack_get_buffer_size (_priv_jack));
146                 }
147                 
148                 _processed_frames = 0;
149                 last_monitor_check = 0;
150
151                 set_jack_callbacks ();
152
153                 if (jack_activate (_priv_jack) == 0) {
154                         _running = true;
155                         _has_run = true;
156                         Running(); /* EMIT SIGNAL */
157                 } else {
158                         // error << _("cannot activate JACK client") << endmsg;
159                 }
160         }
161                 
162         return _running ? 0 : -1;
163 }
164
165 int
166 AudioEngine::stop (bool forever)
167 {
168         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
169
170         if (_priv_jack) {
171                 if (forever) {
172                         disconnect_from_jack ();
173                 } else {
174                         jack_deactivate (_priv_jack);
175                         MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
176                         Stopped(); /* EMIT SIGNAL */
177                 }
178         }
179
180         if (forever) {
181                 stop_metering_thread ();
182         }
183
184         return _running ? -1 : 0;
185 }
186
187
188 void
189 AudioEngine::split_cycle (pframes_t offset)
190 {
191         /* caller must hold process lock */
192
193         Port::increment_global_port_buffer_offset (offset);
194
195         /* tell all Ports that we're going to start a new (split) cycle */
196
197         boost::shared_ptr<Ports> p = ports.reader();
198
199         for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
200                 i->second->cycle_split ();
201         }
202 }
203
204
205 /** Method called by our ::process_thread when there is work to be done.
206  *  @param nframes Number of frames to process.
207  */
208 int
209 AudioEngine::process_callback (pframes_t nframes)
210 {
211         GET_PRIVATE_JACK_POINTER_RET(_jack,0);
212         Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK);
213
214         PT_TIMING_REF;
215         PT_TIMING_CHECK (1);
216
217         /// The number of frames that will have been processed when we've finished
218         pframes_t next_processed_frames;
219
220         /* handle wrap around of total frames counter */
221
222         if (max_framepos - _processed_frames < nframes) {
223                 next_processed_frames = nframes - (max_framepos - _processed_frames);
224         } else {
225                 next_processed_frames = _processed_frames + nframes;
226         }
227
228         if (!tm.locked()) {
229                 /* return having done nothing */
230                 _processed_frames = next_processed_frames;
231                 return 0;
232         }
233
234         if (session_remove_pending) {
235
236                 /* perform the actual session removal */
237
238                 if (session_removal_countdown < 0) {
239
240                         /* fade out over 1 second */
241                         session_removal_countdown = _frame_rate/2;
242                         session_removal_gain = 1.0;
243                         session_removal_gain_step = 1.0/session_removal_countdown;
244
245                 } else if (session_removal_countdown > 0) {
246
247                         /* we'll be fading audio out.
248                            
249                            if this is the last time we do this as part 
250                            of session removal, do a MIDI panic now
251                            to get MIDI stopped. This relies on the fact
252                            that "immediate data" (aka "out of band data") from
253                            MIDI tracks is *appended* after any other data, 
254                            so that it emerges after any outbound note ons, etc.
255                         */
256
257                         if (session_removal_countdown <= nframes) {
258                                 _session->midi_panic ();
259                         }
260
261                 } else {
262                         /* fade out done */
263                         _session = 0;
264                         session_removal_countdown = -1; // reset to "not in progress"
265                         session_remove_pending = false;
266                         session_removed.signal(); // wakes up thread that initiated session removal
267                 }
268         }
269
270         if (_session == 0) {
271
272                 if (!_freewheeling) {
273                         MIDI::Manager::instance()->cycle_start(nframes);
274                         MIDI::Manager::instance()->cycle_end();
275                 }
276
277                 _processed_frames = next_processed_frames;
278
279                 return 0;
280         }
281
282         /* tell all relevant objects that we're starting a new cycle */
283
284         InternalSend::CycleStart (nframes);
285         Port::set_global_port_buffer_offset (0);
286         Port::set_cycle_framecnt (nframes);
287
288         /* tell all Ports that we're starting a new cycle */
289
290         boost::shared_ptr<Ports> p = ports.reader();
291
292         for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
293                 i->second->cycle_start (nframes);
294         }
295
296         /* test if we are freewheeling and there are freewheel signals connected.
297            ardour should act normally even when freewheeling unless /it/ is
298            exporting 
299         */
300
301         if (_freewheeling && !Freewheel.empty()) {
302
303                 Freewheel (nframes);
304
305         } else {
306                 MIDI::Manager::instance()->cycle_start(nframes);
307
308                 if (_session) {
309                         _session->process (nframes);
310                 }
311
312                 MIDI::Manager::instance()->cycle_end();
313         }
314
315         if (_freewheeling) {
316                 return 0;
317         }
318
319         if (!_running) {
320                 _processed_frames = next_processed_frames;
321                 return 0;
322         }
323
324         if (last_monitor_check + monitor_check_interval < next_processed_frames) {
325
326                 boost::shared_ptr<Ports> p = ports.reader();
327
328                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
329
330                         bool x;
331
332                         if (i->second->last_monitor() != (x = i->second->monitoring_input ())) {
333                                 i->second->set_last_monitor (x);
334                                 /* XXX I think this is dangerous, due to
335                                    a likely mutex in the signal handlers ...
336                                 */
337                                 i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
338                         }
339                 }
340                 last_monitor_check = next_processed_frames;
341         }
342
343         if (_session->silent()) {
344
345                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
346
347                         if (i->second->sends_output()) {
348                                 i->second->get_buffer(nframes).silence(nframes);
349                         }
350                 }
351         }
352
353         if (session_remove_pending && session_removal_countdown) {
354
355                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
356
357                         if (i->second->sends_output()) {
358
359                                 boost::shared_ptr<AudioPort> ap = boost::dynamic_pointer_cast<AudioPort> (i->second);
360                                 if (ap) {
361                                         Sample* s = ap->engine_get_whole_audio_buffer ();
362                                         gain_t g = session_removal_gain;
363                                         
364                                         for (pframes_t n = 0; n < nframes; ++n) {
365                                                 *s++ *= g;
366                                                 g -= session_removal_gain_step;
367                                         }
368                                 }
369                         }
370                 }
371                 
372                 if (session_removal_countdown > nframes) {
373                         session_removal_countdown -= nframes;
374                 } else {
375                         session_removal_countdown = 0;
376                 }
377
378                 session_removal_gain -= (nframes * session_removal_gain_step);
379         }
380
381         // Finalize ports
382
383         for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
384                 i->second->cycle_end (nframes);
385         }
386
387         _processed_frames = next_processed_frames;
388
389         PT_TIMING_CHECK (2);
390         
391         return 0;
392 }
393
394
395 void
396 AudioEngine::stop_metering_thread ()
397 {
398         if (m_meter_thread) {
399                 g_atomic_int_set (&m_meter_exit, 1);
400                 m_meter_thread->join ();
401                 m_meter_thread = 0;
402         }
403 }
404
405 void
406 AudioEngine::start_metering_thread ()
407 {
408         if (m_meter_thread == 0) {
409                 g_atomic_int_set (&m_meter_exit, 0);
410                 m_meter_thread = Glib::Threads::Thread::create (boost::bind (&AudioEngine::meter_thread, this));
411         }
412 }
413
414 void
415 AudioEngine::meter_thread ()
416 {
417         pthread_set_name (X_("meter"));
418
419         while (true) {
420                 Glib::usleep (10000); /* 1/100th sec interval */
421                 if (g_atomic_int_get(&m_meter_exit)) {
422                         break;
423                 }
424                 Metering::Meter ();
425         }
426 }
427
428 void
429 AudioEngine::set_session (Session *s)
430 {
431         Glib::Threads::Mutex::Lock pl (_process_lock);
432
433         SessionHandlePtr::set_session (s);
434
435         if (_session) {
436
437                 start_metering_thread ();
438
439                 pframes_t blocksize = jack_get_buffer_size (_jack);
440
441                 /* page in as much of the session process code as we
442                    can before we really start running.
443                 */
444
445                 boost::shared_ptr<Ports> p = ports.reader();
446
447                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
448                         i->second->cycle_start (blocksize);
449                 }
450
451                 _session->process (blocksize);
452                 _session->process (blocksize);
453                 _session->process (blocksize);
454                 _session->process (blocksize);
455                 _session->process (blocksize);
456                 _session->process (blocksize);
457                 _session->process (blocksize);
458                 _session->process (blocksize);
459
460                 for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
461                         i->second->cycle_end (blocksize);
462                 }
463         }
464 }
465
466 void
467 AudioEngine::remove_session ()
468 {
469         Glib::Threads::Mutex::Lock lm (_process_lock);
470
471         if (_running) {
472
473                 stop_metering_thread ();
474
475                 if (_session) {
476                         session_remove_pending = true;
477                         session_removed.wait(_process_lock);
478                 }
479
480         } else {
481                 SessionHandlePtr::set_session (0);
482         }
483
484         remove_all_ports ();
485 }
486
487 void
488 AudioEngine::port_registration_failure (const std::string& portname)
489 {
490         GET_PRIVATE_JACK_POINTER (_jack);
491         string full_portname = jack_client_name;
492         full_portname += ':';
493         full_portname += portname;
494
495
496         jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str());
497         string reason;
498
499         if (p) {
500                 reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
501         } else {
502                 reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME);
503         }
504
505         throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
506 }
507
508 boost::shared_ptr<Port>
509 AudioEngine::register_port (DataType dtype, const string& portname, bool input)
510 {
511         boost::shared_ptr<Port> newport;
512
513         try {
514                 if (dtype == DataType::AUDIO) {
515                         newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput)));
516                 } else if (dtype == DataType::MIDI) {
517                         newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput)));
518                 } else {
519                         throw PortRegistrationFailure("unable to create port (unknown type)");
520                 }
521
522                 RCUWriter<Ports> writer (ports);
523                 boost::shared_ptr<Ports> ps = writer.get_copy ();
524                 ps->insert (make_pair (make_port_name_relative (portname), newport));
525
526                 /* writer goes out of scope, forces update */
527
528                 return newport;
529         }
530
531         catch (PortRegistrationFailure& err) {
532                 throw err;
533         } catch (std::exception& e) {
534                 throw PortRegistrationFailure(string_compose(
535                                 _("unable to create port: %1"), e.what()).c_str());
536         } catch (...) {
537                 throw PortRegistrationFailure("unable to create port (unknown error)");
538         }
539 }
540
541 boost::shared_ptr<Port>
542 AudioEngine::register_input_port (DataType type, const string& portname)
543 {
544         return register_port (type, portname, true);
545 }
546
547 boost::shared_ptr<Port>
548 AudioEngine::register_output_port (DataType type, const string& portname)
549 {
550         return register_port (type, portname, false);
551 }
552
553 int
554 AudioEngine::unregister_port (boost::shared_ptr<Port> port)
555 {
556         /* caller must hold process lock */
557
558         if (!_running) {
559                 /* probably happening when the engine has been halted by JACK,
560                    in which case, there is nothing we can do here.
561                    */
562                 return 0;
563         }
564
565         {
566                 RCUWriter<Ports> writer (ports);
567                 boost::shared_ptr<Ports> ps = writer.get_copy ();
568                 Ports::iterator x = ps->find (make_port_name_relative (port->name()));
569
570                 if (x != ps->end()) {
571                         ps->erase (x);
572                 }
573
574                 /* writer goes out of scope, forces update */
575         }
576
577         ports.flush ();
578
579         return 0;
580 }
581
582 int
583 AudioEngine::connect (const string& source, const string& destination)
584 {
585         int ret;
586
587         if (!_running) {
588                 if (!_has_run) {
589                         fatal << _("connect called before engine was started") << endmsg;
590                         /*NOTREACHED*/
591                 } else {
592                         return -1;
593                 }
594         }
595
596         string s = make_port_name_non_relative (source);
597         string d = make_port_name_non_relative (destination);
598
599
600         boost::shared_ptr<Port> src = get_port_by_name (s);
601         boost::shared_ptr<Port> dst = get_port_by_name (d);
602
603         if (src) {
604                 ret = src->connect (d);
605         } else if (dst) {
606                 ret = dst->connect (s);
607         } else {
608                 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
609                 ret = -1;
610         }
611
612         if (ret > 0) {
613                 /* already exists - no error, no warning */
614         } else if (ret < 0) {
615                 error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"),
616                                         source, s, destination, d)
617                       << endmsg;
618         }
619
620         return ret;
621 }
622
623 int
624 AudioEngine::disconnect (const string& source, const string& destination)
625 {
626         int ret;
627
628         if (!_running) {
629                 if (!_has_run) {
630                         fatal << _("disconnect called before engine was started") << endmsg;
631                         /*NOTREACHED*/
632                 } else {
633                         return -1;
634                 }
635         }
636
637         string s = make_port_name_non_relative (source);
638         string d = make_port_name_non_relative (destination);
639
640         boost::shared_ptr<Port> src = get_port_by_name (s);
641         boost::shared_ptr<Port> dst = get_port_by_name (d);
642
643         if (src) {
644                         ret = src->disconnect (d);
645         } else if (dst) {
646                         ret = dst->disconnect (s);
647         } else {
648                 /* neither port is known to us, and this API isn't intended for use as a general patch bay */
649                 ret = -1;
650         }
651         return ret;
652 }
653
654 int
655 AudioEngine::disconnect (boost::shared_ptr<Port> port)
656 {
657         GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
658
659         if (!_running) {
660                 if (!_has_run) {
661                         fatal << _("disconnect called before engine was started") << endmsg;
662                         /*NOTREACHED*/
663                 } else {
664                         return -1;
665                 }
666         }
667
668         return port->disconnect_all ();
669 }
670
671 ARDOUR::framecnt_t
672 AudioEngine::frame_rate () const
673 {
674         GET_PRIVATE_JACK_POINTER_RET (_jack, 0);
675         if (_frame_rate == 0) {
676                 return (_frame_rate = jack_get_sample_rate (_priv_jack));
677         } else {
678                 return _frame_rate;
679         }
680 }
681
682 size_t
683 AudioEngine::raw_buffer_size (DataType t)
684 {
685         std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t);
686         return (s != _raw_buffer_sizes.end()) ? s->second : 0;
687 }
688
689 ARDOUR::pframes_t
690 AudioEngine::frames_per_cycle () const
691 {
692         GET_PRIVATE_JACK_POINTER_RET (_jack,0);
693         if (_buffer_size == 0) {
694                 return jack_get_buffer_size (_jack);
695         } else {
696                 return _buffer_size;
697         }
698 }
699
700 /** @param name Full or short name of port
701  *  @return Corresponding Port or 0.
702  */
703
704 boost::shared_ptr<Port>
705 AudioEngine::get_port_by_name (const string& portname)
706 {
707         if (!_running) {
708                 if (!_has_run) {
709                         fatal << _("get_port_by_name() called before engine was started") << endmsg;
710                         /*NOTREACHED*/
711                 } else {
712                         boost::shared_ptr<Port> ();
713                 }
714         }
715
716         if (!port_is_mine (portname)) {
717                 /* not an ardour port */
718                 return boost::shared_ptr<Port> ();
719         }
720
721         boost::shared_ptr<Ports> pr = ports.reader();
722         std::string rel = make_port_name_relative (portname);
723         Ports::iterator x = pr->find (rel);
724
725         if (x != pr->end()) {
726                 /* its possible that the port was renamed by some 3rd party and
727                    we don't know about it. check for this (the check is quick
728                    and cheap), and if so, rename the port (which will alter
729                    the port map as a side effect).
730                 */
731                 const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port()));
732                 if (check != rel) {
733                         x->second->set_name (check);
734                 }
735                 return x->second;
736         }
737
738         return boost::shared_ptr<Port> ();
739 }
740
741 void
742 AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
743 {
744         RCUWriter<Ports> writer (ports);
745         boost::shared_ptr<Ports> p = writer.get_copy();
746         Ports::iterator x = p->find (old_relative_name);
747         
748         if (x != p->end()) {
749                 boost::shared_ptr<Port> port = x->second;
750                 p->erase (x);
751                 p->insert (make_pair (new_relative_name, port));
752         }
753 }
754
755 const char **
756 AudioEngine::get_ports (const string& port_name_pattern, const string& type_name_pattern, uint32_t flags)
757 {
758         GET_PRIVATE_JACK_POINTER_RET (_jack,0);
759         if (!_running) {
760                 if (!_has_run) {
761                         fatal << _("get_ports called before engine was started") << endmsg;
762                         /*NOTREACHED*/
763                 } else {
764                         return 0;
765                 }
766         }
767         return jack_get_ports (_priv_jack, port_name_pattern.c_str(), type_name_pattern.c_str(), flags);
768 }
769
770 void
771 AudioEngine::died ()
772 {
773         /* called from a signal handler for SIGPIPE */
774
775         stop_metering_thread ();
776
777         _running = false;
778         _buffer_size = 0;
779         _frame_rate = 0;
780         _jack = 0;
781 }
782
783 bool
784 AudioEngine::can_request_hardware_monitoring ()
785 {
786         GET_PRIVATE_JACK_POINTER_RET (_jack,false);
787         const char ** ports;
788
789         if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) {
790                 return false;
791         }
792
793         free (ports);
794
795         return true;
796 }
797
798 ChanCount
799 AudioEngine::n_physical (unsigned long flags) const
800 {
801         ChanCount c;
802
803         GET_PRIVATE_JACK_POINTER_RET (_jack, c);
804
805         const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags);
806         if (ports == 0) {
807                 return c;
808         }
809
810         for (uint32_t i = 0; ports[i]; ++i) {
811                 if (!strstr (ports[i], "Midi-Through")) {
812                         DataType t (jack_port_type (jack_port_by_name (_jack, ports[i])));
813                         c.set (t, c.get (t) + 1);
814                 }
815         }
816
817         free (ports);
818
819         return c;
820 }
821
822 ChanCount
823 AudioEngine::n_physical_inputs () const
824 {
825         return n_physical (JackPortIsInput);
826 }
827
828 ChanCount
829 AudioEngine::n_physical_outputs () const
830 {
831         return n_physical (JackPortIsOutput);
832 }
833
834 void
835 AudioEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy)
836 {
837         GET_PRIVATE_JACK_POINTER (_jack);
838         const char ** ports;
839
840         if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) {
841                 return;
842         }
843
844         if (ports) {
845                 for (uint32_t i = 0; ports[i]; ++i) {
846                         if (strstr (ports[i], "Midi-Through")) {
847                                 continue;
848                         }
849                         phy.push_back (ports[i]);
850                 }
851                 free (ports);
852         }
853 }
854
855 /** Get physical ports for which JackPortIsOutput is set; ie those that correspond to
856  *  a physical input connector.
857  */
858 void
859 AudioEngine::get_physical_inputs (DataType type, vector<string>& ins)
860 {
861         get_physical (type, JackPortIsOutput, ins);
862 }
863
864 /** Get physical ports for which JackPortIsInput is set; ie those that correspond to
865  *  a physical output connector.
866  */
867 void
868 AudioEngine::get_physical_outputs (DataType type, vector<string>& outs)
869 {
870         get_physical (type, JackPortIsInput, outs);
871 }
872
873
874 int
875 AudioEngine::reset_timebase ()
876 {
877         GET_PRIVATE_JACK_POINTER_RET (_jack, -1);
878         if (_session) {
879                 if (_session->config.get_jack_time_master()) {
880                         _backend->set_time_master (true);
881                 } else {
882                         _backend->set_time_master (false);
883                 }
884         }
885         return 0;
886 }
887
888 void
889 AudioEngine::remove_all_ports ()
890 {
891         /* make sure that JACK callbacks that will be invoked as we cleanup
892          * ports know that they have nothing to do.
893          */
894
895         port_remove_in_progress = true;
896
897         /* process lock MUST be held by caller
898         */
899
900         {
901                 RCUWriter<Ports> writer (ports);
902                 boost::shared_ptr<Ports> ps = writer.get_copy ();
903                 ps->clear ();
904         }
905
906         /* clear dead wood list in RCU */
907
908         ports.flush ();
909
910         port_remove_in_progress = false;
911 }
912
913
914 string
915 AudioEngine::make_port_name_relative (string portname) const
916 {
917         string::size_type len;
918         string::size_type n;
919
920         len = portname.length();
921
922         for (n = 0; n < len; ++n) {
923                 if (portname[n] == ':') {
924                         break;
925                 }
926         }
927
928         if ((n != len) && (portname.substr (0, n) == jack_client_name)) {
929                 return portname.substr (n+1);
930         }
931
932         return portname;
933 }
934
935 string
936 AudioEngine::make_port_name_non_relative (string portname) const
937 {
938         string str;
939
940         if (portname.find_first_of (':') != string::npos) {
941                 return portname;
942         }
943
944         str  = jack_client_name;
945         str += ':';
946         str += portname;
947
948         return str;
949 }
950
951 bool
952 AudioEngine::port_is_mine (const string& portname) const
953 {
954         if (portname.find_first_of (':') != string::npos) {
955                 if (portname.substr (0, jack_client_name.length ()) != jack_client_name) {
956                         return false;
957                 }
958         }
959         return true;
960 }
961
962 bool
963 AudioEngine::port_is_physical (const std::string& portname) const
964 {
965         GET_PRIVATE_JACK_POINTER_RET(_jack, false);
966
967         jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str());
968
969         if (!port) {
970                 return false;
971         }
972
973         return jack_port_flags (port) & JackPortIsPhysical;
974 }
975
976 void
977 AudioEngine::destroy ()
978 {
979         delete _instance;
980         _instance = 0;
981 }
982
983 int
984 AudioEngine::discover_backends ()
985 {
986         vector<std::string> backend_modules;
987         AudioBackend* backend;
988
989         Glib::PatternSpec so_extension_pattern("*.so");
990         Glib::PatternSpec dylib_extension_pattern("*.dylib");
991
992         find_matching_files_in_search_path (backend_search_path (),
993                                             so_extension_pattern, backend_modules);
994
995         find_matching_files_in_search_path (backend_search_path (),
996                                             dylib_extension_pattern, backend_modules);
997
998         DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1"), backend_search_path().to_string()));
999
1000         for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) {
1001                 if ((backend = backend_discover (*i)) != 0) {
1002                         _backends.insert (make_pair (backend->name(), backend));
1003                 }
1004         }
1005 }
1006
1007 AudioBackend*
1008 AudioEngine::backend_discover (string path)
1009 {
1010         Glib::Module* module = new Glib::Module(path);
1011         AudioBackend* (*dfunc)(void);
1012         void* func = 0;
1013
1014         if (!module) {
1015                 error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path,
1016                                 Glib::Module::get_last_error()) << endmsg;
1017                 delete module;
1018                 return 0;
1019         }
1020
1021         if (!module->get_symbol("backend_factory", func)) {
1022                 error << string_compose(_("AudioEngine: module \"%1\" has no factory function."), path) << endmsg;
1023                 error << Glib::Module::get_last_error() << endmsg;
1024                 delete module;
1025                 return 0;
1026         }
1027
1028         dfunc = (AudioBackend* (*)(void))func;
1029         AudioBackend* backend = dfunc();
1030
1031         return backend;
1032 }