From b5239317d4657ad689ef7ef4d11c1fb6ae3e699b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 31 Jul 2013 19:47:20 -0400 Subject: [PATCH] more stuff compiles --- libs/ardour/ardour/audio_backend.h | 23 +- libs/ardour/ardour/audio_port.h | 8 +- libs/ardour/ardour/audioengine.h | 18 +- libs/ardour/ardour/jack_audiobackend.h | 6 +- libs/ardour/ardour/jack_connection.h | 4 +- libs/ardour/ardour/jack_portengine.h | 24 ++- libs/ardour/ardour/midi_port.h | 4 +- libs/ardour/ardour/port_engine.h | 52 +++-- libs/ardour/ardour/port_manager.h | 49 ++++- libs/ardour/ardour/types.h | 7 +- libs/ardour/audioengine.cc | 39 ++-- libs/ardour/jack_audiobackend.cc | 4 +- libs/ardour/jack_connection.cc | 6 +- libs/ardour/jack_portengine.cc | 253 ++++++++++++++++++---- libs/ardour/port.cc | 13 +- libs/ardour/port_manager.cc | 277 ++++++++----------------- libs/ardour/wscript | 1 + 17 files changed, 478 insertions(+), 310 deletions(-) diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h index 4d6d6a6dd8..44525c8353 100644 --- a/libs/ardour/ardour/audio_backend.h +++ b/libs/ardour/ardour/audio_backend.h @@ -33,6 +33,8 @@ namespace ARDOUR { class AudioEngine; +class PortEngine; +class PortManager; class AudioBackend { public: @@ -47,15 +49,18 @@ class AudioBackend { */ virtual std::string name() const = 0; + /** Return a private, type-free pointer to any data + * that might be useful to a concrete implementation + */ virtual void* private_handle() const = 0; - /** return true if the underlying mechanism/API is still available + /** Return true if the underlying mechanism/API is still available * for us to utilize. return false if some or all of the AudioBackend * API can no longer be effectively used. */ virtual bool connected() const = 0; - /** return true if the callback from the underlying mechanism/API + /** Return true if the callback from the underlying mechanism/API * (CoreAudio, JACK, ASIO etc.) occurs in a thread subject to realtime * constraints. Return false otherwise. */ @@ -160,6 +165,8 @@ class AudioBackend { */ virtual int set_systemic_output_latency (uint32_t) = 0; + /* Retrieving parameters */ + virtual std::string device_name () const = 0; virtual float sample_rate () const = 0; virtual uint32_t buffer_size () const = 0; @@ -337,7 +344,17 @@ class AudioBackend { AudioEngine& engine; }; -} +struct AudioBackendInfo { + const char* name; + + int (*instantiate) (const std::string& arg1, const std::string& arg2); + int (*deinstantiate) (void); + + boost::shared_ptr (*backend_factory) (AudioEngine&); + boost::shared_ptr (*portengine_factory) (PortManager&); +}; + +} // namespace #endif /* __libardour_audiobackend_h__ */ diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h index a473dda418..f5affb0580 100644 --- a/libs/ardour/ardour/audio_port.h +++ b/libs/ardour/ardour/audio_port.h @@ -46,10 +46,12 @@ class AudioPort : public Port AudioBuffer& get_audio_buffer (pframes_t nframes); protected: - friend class AudioEngine; - + friend class PortManager; AudioPort (std::string const &, PortFlags); - /* special access for engine only */ + + protected: + friend class AudioEngine; + /* special access for engine only (hah, C++) */ Sample* engine_get_whole_audio_buffer (); private: diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index db1f59d19f..9e9da62ce0 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -61,6 +61,7 @@ class Port; class Session; class ProcessThread; class AudioBackend; +class AudioBackendInfo; class AudioEngine : public SessionHandlePtr, public PortManager { @@ -164,16 +165,6 @@ public: PBD::Signal0 Running; PBD::Signal0 Stopped; - /** Emitted if a Port is registered or unregistered */ - PBD::Signal0 PortRegisteredOrUnregistered; - - /** Emitted if a Port is connected or disconnected. - * The Port parameters are the ports being connected / disconnected, or 0 if they are not known to Ardour. - * The std::string parameters are the (long) port names. - * The bool parameter is true if ports were connected, or false for disconnected. - */ - PBD::Signal5, std::string, boost::weak_ptr, std::string, bool> PortConnectedOrDisconnected; - std::string make_port_name_relative (std::string) const; std::string make_port_name_non_relative (std::string) const; bool port_is_mine (const std::string&) const; @@ -202,7 +193,8 @@ public: static AudioEngine* _instance; - AudioBackend* _backend; + boost::shared_ptr _backend; + Glib::Threads::Mutex _process_lock; Glib::Threads::Cond session_removed; bool session_remove_pending; @@ -239,9 +231,9 @@ public: void parameter_changed (const std::string&); PBD::ScopedConnection config_connection; - typedef std::map BackendMap; + typedef std::map BackendMap; BackendMap _backends; - AudioBackend* backend_discover (const std::string&); + AudioBackendInfo* backend_discover (const std::string&); void drop_backend (); }; diff --git a/libs/ardour/ardour/jack_audiobackend.h b/libs/ardour/ardour/jack_audiobackend.h index 8f6e636d1a..0855b8e90f 100644 --- a/libs/ardour/ardour/jack_audiobackend.h +++ b/libs/ardour/ardour/jack_audiobackend.h @@ -26,6 +26,8 @@ #include +#include + #include #ifdef HAVE_JACK_SESSION #include @@ -39,7 +41,7 @@ class JackConnection; class JACKAudioBackend : public AudioBackend { public: - JACKAudioBackend (AudioEngine& e, void*); + JACKAudioBackend (AudioEngine& e, boost::shared_ptr); ~JACKAudioBackend (); std::string name() const; @@ -98,7 +100,7 @@ class JACKAudioBackend : public AudioBackend { bool get_sync_offset (pframes_t& /*offset*/) const; private: - JackConnection* _jack_connection; //< shared with JACKPortEngine + boost::shared_ptr _jack_connection; //< shared with JACKPortEngine bool _running; bool _freewheeling; std::map _raw_buffer_sizes; diff --git a/libs/ardour/ardour/jack_connection.h b/libs/ardour/ardour/jack_connection.h index 02fb7c7e55..543a70c439 100644 --- a/libs/ardour/ardour/jack_connection.h +++ b/libs/ardour/ardour/jack_connection.h @@ -13,6 +13,8 @@ class JackConnection { JackConnection (const std::string& client_name, const std::string& session_uuid); ~JackConnection (); + const std::string& client_name() const { return _client_name; } + int open (); int close (); bool connected () const { return _jack != 0; } @@ -26,7 +28,7 @@ class JackConnection { private: jack_client_t* volatile _jack; - std::string client_name; + std::string _client_name; std::string session_uuid; }; diff --git a/libs/ardour/ardour/jack_portengine.h b/libs/ardour/ardour/jack_portengine.h index 60aa52fb6b..80e34f3c92 100644 --- a/libs/ardour/ardour/jack_portengine.h +++ b/libs/ardour/ardour/jack_portengine.h @@ -25,6 +25,8 @@ #include +#include + #include "ardour/port_engine.h" #include "ardour/types.h" @@ -35,11 +37,13 @@ class JackConnection; class JACKPortEngine : public PortEngine { public: - JACKPortEngine (void* arg); // argument is a JackConnection + JACKPortEngine (PortManager&, boost::shared_ptr); bool connected() const; void* private_handle() const; + const std::string& my_name() const; + int set_port_name (PortHandle, const std::string&); std::string get_port_name (PortHandle) const; PortHandle* get_port_by_name (const std::string&) const; @@ -48,6 +52,10 @@ class JACKPortEngine : public PortEngine std::string make_port_name_non_relative (const std::string& name) const; bool port_is_mine (const std::string& fullname) const; + int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector&) const; + + DataType port_data_type (PortHandle) const; + PortHandle register_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags); void unregister_port (PortHandle); @@ -85,17 +93,25 @@ class JACKPortEngine : public PortEngine LatencyRange get_latency_range (PortHandle, bool for_playback); LatencyRange get_connected_latency_range (PortHandle, int dir); - void* get_buffer (PortHandle, pframes_t); + bool port_is_physical (PortHandle) const; + void get_physical_outputs (DataType type, std::vector&); + void get_physical_inputs (DataType type, std::vector&); + ChanCount n_physical_outputs () const; + ChanCount n_physical_inputs () const; - pframes_t last_frame_time () const; + void* get_buffer (PortHandle, pframes_t); + framecnt_t last_frame_time () const; + private: - JackConnection* _jack_connection; + boost::shared_ptr _jack_connection; static int _graph_order_callback (void *arg); static void _registration_callback (jack_port_id_t, int, void *); static void _connect_callback (jack_port_id_t, jack_port_id_t, int, void *); + int graph_order_callback (); + void connect_callback (jack_port_id_t, jack_port_id_t, int); }; diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h index e14c7926fb..4a9a2ededc 100644 --- a/libs/ardour/ardour/midi_port.h +++ b/libs/ardour/ardour/midi_port.h @@ -57,9 +57,9 @@ class MidiPort : public Port { MidiBuffer& get_midi_buffer (pframes_t nframes); protected: - friend class AudioEngine; + friend class PortManager; - MidiPort (const std::string& name, PortFlags); + MidiPort (const std::string& name, PortFlags); private: MidiBuffer* _buffer; diff --git a/libs/ardour/ardour/port_engine.h b/libs/ardour/ardour/port_engine.h index 3044426ff9..5992a48a85 100644 --- a/libs/ardour/ardour/port_engine.h +++ b/libs/ardour/ardour/port_engine.h @@ -30,6 +30,8 @@ namespace ARDOUR { +class PortManager; + /** PortEngine is an abstract base class that defines the functionality * required by Ardour. * @@ -74,7 +76,7 @@ namespace ARDOUR { class PortEngine { public: - PortEngine() {} + PortEngine (PortManager& pm) : manager (pm) {} virtual ~PortEngine(); /* We use void* here so that the API can be defined for any implementation. @@ -90,32 +92,37 @@ class PortEngine { virtual bool connected() const = 0; virtual void* private_handle() const = 0; + virtual const std::string& my_name() const = 0; + virtual int set_port_name (PortHandle, const std::string&) = 0; virtual std::string get_port_name (PortHandle) const = 0; virtual PortHandle* get_port_by_name (const std::string&) const = 0; - DataType port_data_type (PortHandle) const; + /* Discovering the set of ports whose names, types and flags match + * specified values. + */ + + virtual int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector&) const = 0; - virtual std::string make_port_name_relative (const std::string& name) const = 0; - virtual std::string make_port_name_non_relative (const std::string& name) const = 0; - virtual bool port_is_mine (const std::string& fullname) const = 0; + virtual DataType port_data_type (PortHandle) const = 0; virtual PortHandle register_port (const std::string& shortname, ARDOUR::DataType, ARDOUR::PortFlags) = 0; - virtual void unregister_port (PortHandle) = 0; + virtual void unregister_port (PortHandle) = 0; + + /* Connection management */ + + virtual int connect (const std::string& src, const std::string& dst) = 0; + virtual int disconnect (const std::string& src, const std::string& dst) = 0; + + virtual int connect (PortHandle, const std::string&) = 0; + virtual int disconnect (PortHandle, const std::string&) = 0; + virtual int disconnect_all (PortHandle) = 0; virtual bool connected (PortHandle) = 0; virtual bool connected_to (PortHandle, const std::string&) = 0; virtual bool physically_connected (PortHandle) = 0; - virtual int get_connections (PortHandle, std::vector&) = 0; - virtual int connect (PortHandle, const std::string&) = 0; - virtual int disconnect (PortHandle, const std::string&) = 0; - virtual int disconnect_all (PortHandle) = 0; - - virtual int connect (const std::string& src, const std::string& dst) = 0; - virtual int disconnect (const std::string& src, const std::string& dst) = 0; - /* MIDI */ virtual void midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index) = 0; @@ -137,9 +144,24 @@ class PortEngine { virtual LatencyRange get_latency_range (PortHandle, bool for_playback) = 0; virtual LatencyRange get_connected_latency_range (PortHandle, int dir) = 0; + /* Discovering physical ports */ + + virtual bool port_is_physical (PortHandle) const = 0; + virtual void get_physical_outputs (DataType type, std::vector&) = 0; + virtual void get_physical_inputs (DataType type, std::vector&) = 0; + virtual ChanCount n_physical_outputs () const = 0; + virtual ChanCount n_physical_inputs () const = 0; + + /* getting the port buffer. untyped (void*) because this will return + * buffers containing different data depending on the port type + */ + virtual void* get_buffer (PortHandle, pframes_t) = 0; - virtual pframes_t last_frame_time () const = 0; + virtual framecnt_t last_frame_time() const = 0; + + protected: + PortManager& manager; }; } diff --git a/libs/ardour/ardour/port_manager.h b/libs/ardour/ardour/port_manager.h index 38c8d8bf98..5838ac66af 100644 --- a/libs/ardour/ardour/port_manager.h +++ b/libs/ardour/ardour/port_manager.h @@ -42,9 +42,10 @@ class PortManager public: typedef std::map > Ports; - PortManager(); + PortManager (); virtual ~PortManager() {} + void set_port_engine (PortEngine& pe); PortEngine& port_engine() { return *_impl; } /* Port registration */ @@ -62,16 +63,28 @@ class PortManager int reestablish_ports (); int reconnect_ports (); + bool connected (const std::string&); + bool connected_to (const std::string&, const std::string&); + bool physically_connected (const std::string&); + int get_connections (const std::string&, std::vector&); + + /* Naming */ + + boost::shared_ptr get_port_by_name (const std::string &); + void port_renamed (const std::string&, const std::string&); + std::string make_port_name_relative (const std::string& name) const; + std::string make_port_name_non_relative (const std::string& name) const; + bool port_is_mine (const std::string& fullname) const; + /* other Port management */ - bool port_is_physical (const std::string&) const; - void get_physical_outputs (DataType type, std::vector&); - void get_physical_inputs (DataType type, std::vector&); - boost::shared_ptr get_port_by_name (const std::string &); - void port_renamed (const std::string&, const std::string&); + bool port_is_physical (const std::string&) const; + void get_physical_outputs (DataType type, std::vector&); + void get_physical_inputs (DataType type, std::vector&); ChanCount n_physical_outputs () const; ChanCount n_physical_inputs () const; - const char ** get_ports (const std::string& port_name_pattern, DataType type, uint32_t flags); + + int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector&); void remove_all_ports (); @@ -94,15 +107,33 @@ class PortManager std::string reason; }; + /* the port engine will invoke these callbacks when the time is right */ + + void registration_callback (); + int graph_order_callback (); + void connect_callback (const std::string&, const std::string&, bool connection); + + bool port_remove_in_progress() const { return _port_remove_in_progress; } + + /** Emitted if a Port is registered or unregistered */ + PBD::Signal0 PortRegisteredOrUnregistered; + + /** Emitted if a Port is connected or disconnected. + * The Port parameters are the ports being connected / disconnected, or 0 if they are not known to Ardour. + * The std::string parameters are the (long) port names. + * The bool parameter is true if ports were connected, or false for disconnected. + */ + PBD::Signal5, std::string, boost::weak_ptr, std::string, bool> PortConnectedOrDisconnected; protected: - PortEngine* _impl; + boost::shared_ptr _impl; SerializedRCUManager ports; + bool _port_remove_in_progress; boost::shared_ptr register_port (DataType type, const std::string& portname, bool input); void port_registration_failure (const std::string& portname); }; -} +} // namespace #endif /* __libardour_port_manager_h__ */ diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 0167909ef3..b00b03e060 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -598,8 +598,11 @@ namespace ARDOUR { /* these values happen to match the constants used by JACK but this equality cannot be assumed. */ - IsInput = 1, - IsOutput = 2, + IsInput = 0x1, + IsOutput = 0x2, + IsPhysical = 0x4, + CanMonitor = 0x8, + IsTerminal = 0x10 }; struct LatencyRange { diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index b24008cd4e..3d1bf6e77e 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -64,8 +64,7 @@ gint AudioEngine::m_meter_exit; AudioEngine* AudioEngine::_instance = 0; AudioEngine::AudioEngine (const std::string& bcn, const std::string& bsu) - : _backend (0) - , session_remove_pending (false) + : session_remove_pending (false) , session_removal_countdown (-1) , monitor_check_interval (INT32_MAX) , last_monitor_check (0) @@ -109,8 +108,7 @@ AudioEngine::drop_backend () { if (_backend) { _backend->stop (); - delete _backend; - _backend = 0; + _backend.reset (); } } @@ -125,7 +123,15 @@ AudioEngine::set_backend (const std::string& name) drop_backend (); - _backend = b->second; + try { + + _backend = b->second->backend_factory (*this); + _impl = b->second->portengine_factory (*this); + + } catch (...) { + error << string_compose (_("Could not create backend for %1"), name) << endmsg; + return -1; + } return 0; } @@ -512,7 +518,6 @@ int AudioEngine::discover_backends () { vector backend_modules; - AudioBackend* backend; _backends.clear (); @@ -528,20 +533,23 @@ AudioEngine::discover_backends () DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1"), backend_search_path().to_string())); for (vector::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) { - if ((backend = backend_discover (*i)) != 0) { - _backends.insert (make_pair (backend->name(), backend)); + + AudioBackendInfo* info; + + if ((info = backend_discover (*i)) != 0) { + _backends.insert (make_pair (info->name, info)); } } return _backends.size(); } -AudioBackend* +AudioBackendInfo* AudioEngine::backend_discover (const string& path) { Glib::Module* module = new Glib::Module(path); - AudioBackend* (*dfunc)(void); - void* func = 0; + AudioBackendInfo* info; + void* sym = 0; if (!module) { error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path, @@ -550,17 +558,16 @@ AudioEngine::backend_discover (const string& path) return 0; } - if (!module->get_symbol("backend_factory", func)) { - error << string_compose(_("AudioEngine: module \"%1\" has no factory function."), path) << endmsg; + if (!module->get_symbol("descriptor", sym)) { + error << string_compose(_("AudioEngine: backend at \"%1\" has no descriptor."), path) << endmsg; error << Glib::Module::get_last_error() << endmsg; delete module; return 0; } - dfunc = (AudioBackend* (*)(void))func; - AudioBackend* backend = dfunc(); + info = (AudioBackendInfo*) sym; - return backend; + return info; } /* BACKEND PROXY WRAPPERS */ diff --git a/libs/ardour/jack_audiobackend.cc b/libs/ardour/jack_audiobackend.cc index 7575e8387e..b993135f5a 100644 --- a/libs/ardour/jack_audiobackend.cc +++ b/libs/ardour/jack_audiobackend.cc @@ -42,9 +42,9 @@ using std::vector; #define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; } #define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; } -JACKAudioBackend::JACKAudioBackend (AudioEngine& e, void* jc) +JACKAudioBackend::JACKAudioBackend (AudioEngine& e, boost::shared_ptr jc) : AudioBackend (e) - , _jack_connection (static_cast(jc)) + , _jack_connection (jc) , _running (false) , _freewheeling (false) , _target_sample_rate (48000) diff --git a/libs/ardour/jack_connection.cc b/libs/ardour/jack_connection.cc index b6ac28b22a..d2b69c31fb 100644 --- a/libs/ardour/jack_connection.cc +++ b/libs/ardour/jack_connection.cc @@ -45,7 +45,7 @@ static void jack_halted_info_callback (jack_status_t code, const char* reason, v JackConnection::JackConnection (const std::string& arg1, const std::string& arg2) : _jack (0) - , client_name (arg1) + , _client_name (arg1) , session_uuid (arg2) { } @@ -72,12 +72,12 @@ JackConnection::open () global_epa->restore (); } - if ((_jack = jack_client_open (client_name.c_str(), JackSessionID, &status, session_uuid.c_str())) == 0) { + if ((_jack = jack_client_open (_client_name.c_str(), JackSessionID, &status, session_uuid.c_str())) == 0) { return -1; } if (status & JackNameNotUnique) { - client_name = jack_get_client_name (_jack); + _client_name = jack_get_client_name (_jack); } /* attach halted handler */ diff --git a/libs/ardour/jack_portengine.cc b/libs/ardour/jack_portengine.cc index b2534d47f5..4a6f3a1fca 100644 --- a/libs/ardour/jack_portengine.cc +++ b/libs/ardour/jack_portengine.cc @@ -1,5 +1,60 @@ -JACKPortEngine::init () +#define GET_PRIVATE_JACK_POINTER(localvar) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return; } +#define GET_PRIVATE_JACK_POINTER_RET(localvar,r) jack_client_t* localvar = _jack_connection->jack(); if (!(localvar)) { return r; } + +static uint32_t +ardour_port_flags_to_jack_flags (PortFlags flags) +{ + uint32_t jack_flags = 0; + + if (flags & PortIsInput) { + jack_flags |= JackPortIsInput; + } + if (flags & IsInput) { + jack_flags |= JackPortIsOutput; + } + if (flags & IsOutput) { + jack_flags |= JackPortIsTerminal; + } + if (flags & IsPhysical) { + jack_flags |= JackPortIsPhysical; + } + if (flags & CanMonitor) { + jack_flags |= JackPortCanMonitor; + } + + return jack_flags; +} + +static DataType +jack_port_type_to_ardour_data_type (const char* jack_type) +{ + if (strcmp (jack_type, JACK_DEFAULT_AUDIO_TYPE) == 0) { + return DataType::AUDIO; + } else if (strcmp (jack_type, JACK_DEFAULT_MIDI_TYPE) == 0) { + return DataType::MIDI; + } + return DataType::NIL; +} + +static const char* +ardour_data_type_to_jack_port_type (DataType d) { + switch (d) { + case DataType::AUDIO: + return JACK_DEFAULT_AUDIO_TYPE; + case DataType::MIDI: + return JACK_DEFAULT_MIDI_TYPE; + } + + return ""; +} + +JACKPortEngine::JACKPortEngine (PortManager& pm, boost::shared_ptr jc) + : PortEngine (pm) + , _jack_connection (jc) +{ + jack_client_t* client = _jack_connection-> + jack_set_port_registration_callback (_priv_jack, _registration_callback, this); jack_set_port_connect_callback (_priv_jack, _connect_callback, this); jack_set_graph_order_callback (_priv_jack, _graph_order_callback, this); @@ -8,67 +63,46 @@ JACKPortEngine::init () void JACKPortEngine::_registration_callback (jack_port_id_t /*id*/, int /*reg*/, void* arg) { - JACKPortEngine* pm = static_cast (arg); - - if (!pm->port_remove_in_progress) { - pm->engine.PortRegisteredOrUnregistered (); /* EMIT SIGNAL */ - } + static_cast (arg)->_manager->registration_callback (); } void JACKPortEngine::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn, void* arg) { - JACKPortEngine* pm = static_cast (arg); - pm->connect_callback (id_a, id_b, conn); + static_cast (arg)->connect_callback (id_a, id_b, conn); } void JACKPortEngine::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn) { - if (port_remove_in_progress) { + if (_manager->port_remove_in_progress()) { return; } GET_PRIVATE_JACK_POINTER (_priv_jack); - jack_port_t* jack_port_a = jack_port_by_id (_priv_jack, id_a); - jack_port_t* jack_port_b = jack_port_by_id (_priv_jack, id_b); + jack_port_t* a = jack_port_by_id (_priv_jack, id_a); + jack_port_t* b = jack_port_by_id (_priv_jack, id_b); - boost::shared_ptr port_a; - boost::shared_ptr port_b; - Ports::iterator x; - boost::shared_ptr pr = ports.reader (); - - x = pr->find (make_port_name_relative (jack_port_name (jack_port_a))); - if (x != pr->end()) { - port_a = x->second; - } - - x = pr->find (make_port_name_relative (jack_port_name (jack_port_b))); - if (x != pr->end()) { - port_b = x->second; - } - - PortConnectedOrDisconnected ( - port_a, jack_port_name (jack_port_a), - port_b, jack_port_name (jack_port_b), - conn == 0 ? false : true - ); /* EMIT SIGNAL */ + _manager->connect_callback (jack_port_name (a), jack_port_name (b), conn == 0 ? false : true); } int JACKPortEngine::_graph_order_callback (void *arg) { - JACKPortEngine* pm = static_cast (arg); + return static_cast (arg)->graph_order_callback (); +} - if (pm->connected() && !pm->port_remove_in_progress) { - pm->engine.GraphReordered (); /* EMIT SIGNAL */ +int +JACKPortEngine::graph_order_callback () +{ + if (_jack_connection->connected()) { + _manager->graph_order_callback (); } - + return 0; } - JACKPortEngine::physically_connected (PortHandle p) { jack_port_t* _jack_port = (jack_port_t*) p; @@ -102,13 +136,148 @@ JACKPortEngine::physically_connected (PortHandle p) DataType JACKPortEngine::port_data_type (PortHandle p) { - const char* t = jack_port_type (p); + return jack_port_type_to_ardour_data_type (jack_port_type (p)); +} - if (strcmp (p, JACK_DEFAULT_AUDIO_TYPE) == 0) { - return DataType::AUDIO; - } else if (strcmp (p, JACK_DEFAULT_MIDI_TYPE) == 0) { - return DataType::MIDI; +const string& +JACKPortEngine::my_name() const +{ + return _client_name; +} + +bool +JACKPortEngine::port_is_physical (PortHandle* ph) const +{ + if (!ph) { + return false; + } + + return jack_port_flags (ph) & JackPortIsPhysical; +} + +int +JACKPortEngine::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector& s) +{ + + GET_PRIVATE_JACK_POINTER_RET (_priv_jack,0); + + const char** ports = jack_get_ports (_priv_jack, port_name_pattern.c_str(), + ardour_data_type_to_jack_port_type (type), + ardour_port_flags_to_jack_flags (flags)); + + if (ports == 0) { + return s; } - return DataType::NIL; + for (uint32_t i = 0; ports[i]; ++i) { + s.push_back (ports[i]); + jack_free (ports[i]); + } + + jack_free (ports); + + return s.size(); +} + +ChanCount +JACKPortEngine::n_physical (unsigned long flags) const +{ + ChanCount c; + + GET_PRIVATE_JACK_POINTER_RET (_jack, c); + + const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags); + + if (ports) { + for (uint32_t i = 0; ports[i]; ++i) { + if (!strstr (ports[i], "Midi-Through")) { + DataType t (jack_port_type (jack_port_by_name (_jack, ports[i]))); + c.set (t, c.get (t) + 1); + jack_free (ports[i]); + } + } + + jack_free (ports); + } + + return c; +} + +ChanCount +JACKPortEngine::n_physical_inputs () const +{ + return n_physical (JackPortIsInput); +} + +ChanCount +JACKPortEngine::n_physical_outputs () const +{ + return n_physical (JackPortIsOutput); +} + +void +JACKPortEngine::get_physical (DataType type, unsigned long flags, vector& phy) +{ + GET_PRIVATE_JACK_POINTER (_priv_jack); + const char ** ports; + + if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) { + return; + } + + if (ports) { + for (uint32_t i = 0; ports[i]; ++i) { + if (strstr (ports[i], "Midi-Through")) { + continue; + } + phy.push_back (ports[i]); + jack_free (ports[i]); + } + jack_free (ports); + } +} + +/** Get physical ports for which JackPortIsOutput is set; ie those that correspond to + * a physical input connector. + */ +void +JACKPortEngine::get_physical_inputs (DataType type, vector& ins) +{ + get_physical (type, JackPortIsOutput, ins); +} + +/** Get physical ports for which JackPortIsInput is set; ie those that correspond to + * a physical output connector. + */ +void +JACKPortEngine::get_physical_outputs (DataType type, vector& outs) +{ + get_physical (type, JackPortIsInput, outs); +} + + +bool +JACKPortEngine::can_request_hardware_monitoring () +{ + GET_PRIVATE_JACK_POINTER_RET (_priv_jack,false); + const char ** ports; + + if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) { + return false; + } + + for (uint32_t i = 0; ports[i]; ++i) { + jack_free (ports[i]); + } + + jack_free (ports); + + return true; +} + +framecnt_t +JACKPortEngine::last_frame_time () const +{ + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0); + return jack_last_frame_time (_priv_jack); } diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index fea2a041e0..5aa6ad0ae7 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -49,6 +49,7 @@ pframes_t Port::_cycle_nframes = 0; * repeated phrase */ #define port_engine AudioEngine::instance()->port_engine() +#define port_manager AudioEngine::instance() /** @param n Port short name */ Port::Port (std::string const & n, DataType t, PortFlags f) @@ -111,7 +112,7 @@ Port::disconnect_all () /* a cheaper, less hacky way to do boost::shared_from_this() ... */ - boost::shared_ptr pself = AudioEngine::instance()->get_port_by_name (name()); + boost::shared_ptr pself = port_manager->get_port_by_name (name()); PostDisconnect (pself, boost::shared_ptr()); // emit signal return 0; @@ -131,7 +132,7 @@ Port::connected_to (std::string const & o) const return false; } - return port_engine.connected_to (_port_handle, port_engine.make_port_name_non_relative (o)); + return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o)); } int @@ -143,8 +144,8 @@ Port::get_connections (std::vector & c) const int Port::connect (std::string const & other) { - std::string const other_name = port_engine.make_port_name_non_relative (other); - std::string const our_name = port_engine.make_port_name_non_relative (_name); + std::string const other_name = AudioEngine::instance()->make_port_name_non_relative (other); + std::string const our_name = AudioEngine::instance()->make_port_name_non_relative (_name); int r = 0; @@ -168,8 +169,8 @@ Port::connect (std::string const & other) int Port::disconnect (std::string const & other) { - std::string const other_fullname = port_engine.make_port_name_non_relative (other); - std::string const this_fullname = port_engine.make_port_name_non_relative (_name); + std::string const other_fullname = port_manager->make_port_name_non_relative (other); + std::string const this_fullname = port_manager->make_port_name_non_relative (_name); int r = 0; diff --git a/libs/ardour/port_manager.cc b/libs/ardour/port_manager.cc index 0c7f4b46e5..9c5eaa998b 100644 --- a/libs/ardour/port_manager.cc +++ b/libs/ardour/port_manager.cc @@ -17,24 +17,35 @@ */ +#include "pbd/error.h" + +#include "midi++/manager.h" #include "ardour/port_manager.h" +#include "ardour/audio_port.h" +#include "ardour/midi_port.h" + +#include "i18n.h" using namespace ARDOUR; +using namespace PBD; +using std::string; +using std::vector; PortManager::PortManager () - , ports (new Ports) + : ports (new Ports) + , _port_remove_in_progress (false) { } void -AudioEngine::remove_all_ports () +PortManager::remove_all_ports () { /* make sure that JACK callbacks that will be invoked as we cleanup * ports know that they have nothing to do. */ - port_remove_in_progress = true; + _port_remove_in_progress = true; /* process lock MUST be held by caller */ @@ -49,15 +60,16 @@ AudioEngine::remove_all_ports () ports.flush (); - port_remove_in_progress = false; + _port_remove_in_progress = false; } string -AudioEngine::make_port_name_relative (const string& portname) const +PortManager::make_port_name_relative (const string& portname) const { string::size_type len; string::size_type n; + string self = _impl->my_name(); len = portname.length(); @@ -67,7 +79,7 @@ AudioEngine::make_port_name_relative (const string& portname) const } } - if ((n != len) && (portname.substr (0, n) == jack_client_name)) { + if ((n != len) && (portname.substr (0, n) == self)) { return portname.substr (n+1); } @@ -75,7 +87,7 @@ AudioEngine::make_port_name_relative (const string& portname) const } string -AudioEngine::make_port_name_non_relative (const string& portname) const +PortManager::make_port_name_non_relative (const string& portname) const { string str; @@ -83,7 +95,7 @@ AudioEngine::make_port_name_non_relative (const string& portname) const return portname; } - str = jack_client_name; + str = _impl->my_name(); str += ':'; str += portname; @@ -91,136 +103,40 @@ AudioEngine::make_port_name_non_relative (const string& portname) const } bool -AudioEngine::port_is_mine (const string& portname) const +PortManager::port_is_mine (const string& portname) const { + string self = _impl->my_name(); + if (portname.find_first_of (':') != string::npos) { - if (portname.substr (0, jack_client_name.length ()) != jack_client_name) { + if (portname.substr (0, self.length ()) != self) { return false; } } - return true; -} - -bool -AudioEngine::port_is_physical (const std::string& portname) const -{ - GET_PRIVATE_JACK_POINTER_RET(_jack, false); - - jack_port_t *port = jack_port_by_name (_priv_jack, portname.c_str()); - - if (!port) { - return false; - } - - return jack_port_flags (port) & JackPortIsPhysical; -} - -ChanCount -AudioEngine::n_physical (unsigned long flags) const -{ - ChanCount c; - - GET_PRIVATE_JACK_POINTER_RET (_jack, c); - - const char ** ports = jack_get_ports (_priv_jack, NULL, NULL, JackPortIsPhysical | flags); - if (ports == 0) { - return c; - } - - for (uint32_t i = 0; ports[i]; ++i) { - if (!strstr (ports[i], "Midi-Through")) { - DataType t (jack_port_type (jack_port_by_name (_jack, ports[i]))); - c.set (t, c.get (t) + 1); - } - } - - free (ports); - - return c; -} - -ChanCount -AudioEngine::n_physical_inputs () const -{ - return n_physical (JackPortIsInput); -} - -ChanCount -AudioEngine::n_physical_outputs () const -{ - return n_physical (JackPortIsOutput); -} - -void -AudioEngine::get_physical (DataType type, unsigned long flags, vector& phy) -{ - GET_PRIVATE_JACK_POINTER (_jack); - const char ** ports; - - if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) { - return; - } - if (ports) { - for (uint32_t i = 0; ports[i]; ++i) { - if (strstr (ports[i], "Midi-Through")) { - continue; - } - phy.push_back (ports[i]); - } - free (ports); - } -} - -/** Get physical ports for which JackPortIsOutput is set; ie those that correspond to - * a physical input connector. - */ -void -AudioEngine::get_physical_inputs (DataType type, vector& ins) -{ - get_physical (type, JackPortIsOutput, ins); -} - -/** Get physical ports for which JackPortIsInput is set; ie those that correspond to - * a physical output connector. - */ -void -AudioEngine::get_physical_outputs (DataType type, vector& outs) -{ - get_physical (type, JackPortIsInput, outs); + return true; } - bool -AudioEngine::can_request_hardware_monitoring () +PortManager::port_is_physical (const std::string& portname) const { - GET_PRIVATE_JACK_POINTER_RET (_jack,false); - const char ** ports; - - if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) { + PortEngine::PortHandle ph = _impl->get_port_by_name (portname); + if (!ph) { return false; } - free (ports); - - return true; + return _impl->port_is_physical (ph); } - /** @param name Full or short name of port * @return Corresponding Port or 0. */ boost::shared_ptr -AudioEngine::get_port_by_name (const string& portname) +PortManager::get_port_by_name (const string& portname) { - if (!_running) { - if (!_has_run) { - fatal << _("get_port_by_name() called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - boost::shared_ptr (); - } + if (!_impl->connected()) { + fatal << _("get_port_by_name() called before engine was started") << endmsg; + /*NOTREACHED*/ } if (!port_is_mine (portname)) { @@ -238,7 +154,7 @@ AudioEngine::get_port_by_name (const string& portname) and cheap), and if so, rename the port (which will alter the port map as a side effect). */ - const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port())); + const std::string check = make_port_name_relative (_impl->get_port_name (x->second->port_handle())); if (check != rel) { x->second->set_name (check); } @@ -249,7 +165,7 @@ AudioEngine::get_port_by_name (const string& portname) } void -AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name) +PortManager::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name) { RCUWriter writer (ports); boost::shared_ptr p = writer.get_copy(); @@ -262,66 +178,42 @@ AudioEngine::port_renamed (const std::string& old_relative_name, const std::stri } } -const char ** -AudioEngine::get_ports (const string& port_name_pattern, DataType type, uint32_t flags) +int +PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector& s) { - GET_PRIVATE_JACK_POINTER_RET (_jack,0); - if (!_running) { - if (!_has_run) { - fatal << _("get_ports called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - return 0; - } - } - - const char* jack_type_string; - - switch (type) { - case DataType::AUDIO: - jack_type_string = JACK_DEFAULT_AUDIO_TYPE; - break; - case DataType::AUDIO: - jack_type_string = JACK_DEFAULT_MIDI_TYPE; - break; - case DataType::NIL - return 0; - } - - return jack_get_ports (_priv_jack, port_name_pattern.c_str(), jack_type_string, flags); + return _impl->get_ports (port_name_pattern, type, flags, s); } void -AudioEngine::port_registration_failure (const std::string& portname) +PortManager::port_registration_failure (const std::string& portname) { - GET_PRIVATE_JACK_POINTER (_jack); - string full_portname = jack_client_name; + string full_portname = _impl->my_name(); full_portname += ':'; full_portname += portname; - jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str()); + PortEngine::PortHandle p = _impl->get_port_by_name (full_portname); string reason; if (p) { reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname); } else { - 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); + reason = string_compose (_("No more ports are available. You will need to stop %1 and restart with more ports if you need this many tracks."), PROGRAM_NAME); } throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str()); } boost::shared_ptr -AudioEngine::register_port (DataType dtype, const string& portname, bool input) +PortManager::register_port (DataType dtype, const string& portname, bool input) { boost::shared_ptr newport; try { if (dtype == DataType::AUDIO) { - newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput))); + newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput))); } else if (dtype == DataType::MIDI) { - newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput))); + newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput))); } else { throw PortRegistrationFailure("unable to create port (unknown type)"); } @@ -346,23 +238,23 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input) } boost::shared_ptr -AudioEngine::register_input_port (DataType type, const string& portname) +PortManager::register_input_port (DataType type, const string& portname) { return register_port (type, portname, true); } boost::shared_ptr -AudioEngine::register_output_port (DataType type, const string& portname) +PortManager::register_output_port (DataType type, const string& portname) { return register_port (type, portname, false); } int -AudioEngine::unregister_port (boost::shared_ptr port) +PortManager::unregister_port (boost::shared_ptr port) { /* caller must hold process lock */ - if (!_running) { + if (!_impl->connected()) { /* probably happening when the engine has been halted by JACK, in which case, there is nothing we can do here. */ @@ -399,23 +291,17 @@ PortManager::connected (const string& port_name) } int -AudioEngine::connect (const string& source, const string& destination) +PortManager::connect (const string& source, const string& destination) { int ret; - if (!_running) { - if (!_has_run) { - fatal << _("connect called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - return -1; - } + if (!_impl->connected()) { + return -1; } string s = make_port_name_non_relative (source); string d = make_port_name_non_relative (destination); - boost::shared_ptr src = get_port_by_name (s); boost::shared_ptr dst = get_port_by_name (d); @@ -440,17 +326,12 @@ AudioEngine::connect (const string& source, const string& destination) } int -AudioEngine::disconnect (const string& source, const string& destination) +PortManager::disconnect (const string& source, const string& destination) { int ret; - if (!_running) { - if (!_has_run) { - fatal << _("disconnect called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - return -1; - } + if (!_impl->connected()) { + return -1; } string s = make_port_name_non_relative (source); @@ -471,19 +352,8 @@ AudioEngine::disconnect (const string& source, const string& destination) } int -AudioEngine::disconnect (boost::shared_ptr port) +PortManager::disconnect (boost::shared_ptr port) { - GET_PRIVATE_JACK_POINTER_RET (_jack,-1); - - if (!_running) { - if (!_has_run) { - fatal << _("disconnect called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - return -1; - } - } - return port->disconnect_all (); } @@ -518,7 +388,7 @@ PortManager::reconnect_ports () /* re-establish connections */ - for (i = p->begin(); i != p->end(); ++i) { + for (Ports::iterator i = p->begin(); i != p->end(); ++i) { i->second->reconnect (); } @@ -526,3 +396,36 @@ PortManager::reconnect_ports () return 0; } + +void +PortManager::connect_callback (const string& a, const string& b, bool conn) +{ + boost::shared_ptr port_a; + boost::shared_ptr port_b; + Ports::iterator x; + boost::shared_ptr pr = ports.reader (); + + x = pr->find (make_port_name_relative (a)); + if (x != pr->end()) { + port_a = x->second; + } + + x = pr->find (make_port_name_relative (b)); + if (x != pr->end()) { + port_b = x->second; + } + + PortConnectedOrDisconnected ( + port_a, a, + port_b, b, + conn + ); /* EMIT SIGNAL */ +} + +void +PortManager::registration_callback () +{ + if (!_port_remove_in_progress) { + PortRegisteredOrUnregistered (); /* EMIT SIGNAL */ + } +} diff --git a/libs/ardour/wscript b/libs/ardour/wscript index a4749d95aa..48cfda7bc2 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -148,6 +148,7 @@ libardour_sources = [ 'plugin_manager.cc', 'port.cc', 'port_insert.cc', + 'port_manager.cc', 'port_set.cc', 'process_thread.cc', 'processor.cc', -- 2.30.2