From 682ebad62bdc85df151ad0b81dc27cc9f3e71cec Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 1 Aug 2013 14:43:12 -0400 Subject: [PATCH] full compilation and linking (coding not finished, will not run) --- libs/ardour/ardour/audio_backend.h | 15 +- libs/ardour/ardour/audioengine.h | 18 +- libs/ardour/ardour/jack_audiobackend.h | 2 + libs/ardour/ardour/jack_portengine.h | 25 +- libs/ardour/ardour/port_engine.h | 21 +- libs/ardour/ardour/port_manager.h | 1 - libs/ardour/ardour/slave.h | 6 +- libs/ardour/audioengine.cc | 178 +++++++++++--- libs/ardour/bundle.cc | 4 +- libs/ardour/jack_audiobackend.cc | 7 + libs/ardour/jack_portengine.cc | 313 ++++++++++++++++++++----- libs/ardour/jack_slave.cc | 33 +-- libs/ardour/port.cc | 12 - libs/ardour/port_manager.cc | 71 ++++-- libs/ardour/route.cc | 10 +- libs/ardour/session.cc | 6 +- libs/ardour/session_export.cc | 2 +- libs/ardour/session_state.cc | 2 +- libs/ardour/session_transport.cc | 20 +- libs/ardour/wscript | 4 +- libs/midi++2/jack_midi_port.cc | 2 +- 21 files changed, 538 insertions(+), 214 deletions(-) diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h index 44525c8353..3b68432b6f 100644 --- a/libs/ardour/ardour/audio_backend.h +++ b/libs/ardour/ardour/audio_backend.h @@ -296,18 +296,17 @@ class AudioBackend { * It is extremely likely that any implementation will use a DLL, since * this function can be called from any thread, at any time, and must be * able to accurately determine the correct sample time. + * + * Can be called from any thread. */ virtual pframes_t sample_time () = 0; - /** return the time according to the sample clock in use when the current - * buffer process cycle began. - * - * Can ONLY be called from within a process() callback tree (which - * implies that it can only be called by a process thread) + /** Return the time according to the sample clock in use when the most + * recent buffer process cycle began. Can be called from any thread. */ virtual pframes_t sample_time_at_cycle_start () = 0; - /** return the time since the current buffer process cycle started, + /** Return the time since the current buffer process cycle started, * in samples, according to the sample clock in use. * * Can ONLY be called from within a process() callback tree (which @@ -315,7 +314,7 @@ class AudioBackend { */ virtual pframes_t samples_since_cycle_start () = 0; - /** return true if it possible to determine the offset in samples of the + /** Return true if it possible to determine the offset in samples of the * first video frame that starts within the current buffer process cycle, * measured from the first sample of the cycle. If returning true, * set @param offset to that offset. @@ -339,6 +338,8 @@ class AudioBackend { * when that function returns. */ virtual int create_process_thread (boost::function func, pthread_t*, size_t stacksize) = 0; + + virtual void update_latencies () = 0; protected: AudioEngine& engine; diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 9e9da62ce0..0bbbe90ef4 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -108,6 +108,16 @@ public: bool is_realtime() const; bool connected() const; + int set_device_name (const std::string&); + int set_sample_rate (float); + int set_buffer_size (uint32_t); + int set_sample_format (SampleFormat); + int set_interleaved (bool yn); + int set_input_channels (uint32_t); + int set_output_channels (uint32_t); + int set_systemic_input_latency (uint32_t); + int set_systemic_output_latency (uint32_t); + /* END BACKEND PROXY API */ bool freewheeling() const { return _freewheeling; } @@ -115,7 +125,9 @@ public: Glib::Threads::Mutex& process_lock() { return _process_lock; } - int request_buffer_size (pframes_t); + int request_buffer_size (pframes_t samples) { + return set_buffer_size (samples); + } framecnt_t processed_frames() const { return _processed_frames; } @@ -165,10 +177,6 @@ public: PBD::Signal0 Running; PBD::Signal0 Stopped; - 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; - static AudioEngine* instance() { return _instance; } static void destroy(); void died (); diff --git a/libs/ardour/ardour/jack_audiobackend.h b/libs/ardour/ardour/jack_audiobackend.h index 0855b8e90f..7104b814c2 100644 --- a/libs/ardour/ardour/jack_audiobackend.h +++ b/libs/ardour/ardour/jack_audiobackend.h @@ -99,6 +99,8 @@ class JACKAudioBackend : public AudioBackend { int set_time_master (bool /*yn*/); bool get_sync_offset (pframes_t& /*offset*/) const; + void update_latencies (); + private: boost::shared_ptr _jack_connection; //< shared with JACKPortEngine bool _running; diff --git a/libs/ardour/ardour/jack_portengine.h b/libs/ardour/ardour/jack_portengine.h index 80e34f3c92..bee87532d3 100644 --- a/libs/ardour/ardour/jack_portengine.h +++ b/libs/ardour/ardour/jack_portengine.h @@ -38,8 +38,8 @@ class JACKPortEngine : public PortEngine { public: JACKPortEngine (PortManager&, boost::shared_ptr); + ~JACKPortEngine(); - bool connected() const; void* private_handle() const; const std::string& my_name() const; @@ -48,10 +48,6 @@ class JACKPortEngine : public PortEngine std::string get_port_name (PortHandle) const; PortHandle* get_port_by_name (const std::string&) const; - 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; - int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector&) const; DataType port_data_type (PortHandle) const; @@ -62,19 +58,16 @@ class JACKPortEngine : public PortEngine bool connected (PortHandle); bool connected_to (PortHandle, const std::string&); bool physically_connected (PortHandle); - int get_connections (PortHandle, std::vector&); - int connect (PortHandle, const std::string&); int disconnect (PortHandle, const std::string&); int disconnect_all (PortHandle); - int connect (const std::string& src, const std::string& dst); int disconnect (const std::string& src, const std::string& dst); /* MIDI */ - void midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index); + int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index); int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size); uint32_t get_midi_event_count (void* port_buffer); void midi_clear (void* port_buffer); @@ -91,7 +84,8 @@ class JACKPortEngine : public PortEngine void set_latency_range (PortHandle, bool for_playback, LatencyRange); LatencyRange get_latency_range (PortHandle, bool for_playback); - LatencyRange get_connected_latency_range (PortHandle, int dir); + + /* Physical ports */ bool port_is_physical (PortHandle) const; void get_physical_outputs (DataType type, std::vector&); @@ -99,9 +93,13 @@ class JACKPortEngine : public PortEngine ChanCount n_physical_outputs () const; ChanCount n_physical_inputs () const; + /* Getting access to the data buffer for a port */ + void* get_buffer (PortHandle, pframes_t); - framecnt_t last_frame_time () const; + /* Miscellany */ + + pframes_t sample_time_at_cycle_start (); private: boost::shared_ptr _jack_connection; @@ -110,10 +108,11 @@ class JACKPortEngine : public PortEngine 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); + ChanCount n_physical (unsigned long flags) const; + void get_physical (DataType type, unsigned long flags, std::vector& phy) const; + }; } // namespace diff --git a/libs/ardour/ardour/port_engine.h b/libs/ardour/ardour/port_engine.h index 5992a48a85..e63c52630d 100644 --- a/libs/ardour/ardour/port_engine.h +++ b/libs/ardour/ardour/port_engine.h @@ -77,7 +77,7 @@ class PortManager; class PortEngine { public: PortEngine (PortManager& pm) : manager (pm) {} - virtual ~PortEngine(); + virtual ~PortEngine() {} /* We use void* here so that the API can be defined for any implementation. * @@ -89,7 +89,6 @@ class PortEngine { typedef void* PortHandle; - virtual bool connected() const = 0; virtual void* private_handle() const = 0; virtual const std::string& my_name() const = 0; @@ -125,10 +124,10 @@ class PortEngine { /* MIDI */ - virtual void midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index) = 0; + virtual int midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index) = 0; virtual int midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size) = 0; - virtual uint32_t get_midi_event_count (void* port_buffer); - virtual void midi_clear (void* port_buffer); + virtual uint32_t get_midi_event_count (void* port_buffer) = 0; + virtual void midi_clear (void* port_buffer) = 0; /* Monitoring */ @@ -142,7 +141,6 @@ class PortEngine { virtual void set_latency_range (PortHandle, bool for_playback, LatencyRange) = 0; virtual LatencyRange get_latency_range (PortHandle, bool for_playback) = 0; - virtual LatencyRange get_connected_latency_range (PortHandle, int dir) = 0; /* Discovering physical ports */ @@ -158,7 +156,16 @@ class PortEngine { virtual void* get_buffer (PortHandle, pframes_t) = 0; - virtual framecnt_t last_frame_time() const = 0; + /* MIDI ports (the ones in libmidi++) need this to be able to correctly + * schedule MIDI events within their buffers. It is a bit odd that we + * expose this here, because it is also exposed by AudioBackend, but they + * only have access to a PortEngine object, not an AudioBackend. + * + * Return the time according to the sample clock in use when the current + * buffer process cycle began. + * + */ + virtual pframes_t sample_time_at_cycle_start () = 0; protected: PortManager& manager; diff --git a/libs/ardour/ardour/port_manager.h b/libs/ardour/ardour/port_manager.h index 5838ac66af..d88143d110 100644 --- a/libs/ardour/ardour/port_manager.h +++ b/libs/ardour/ardour/port_manager.h @@ -59,7 +59,6 @@ class PortManager int connect (const std::string& source, const std::string& destination); int disconnect (const std::string& source, const std::string& destination); int disconnect (boost::shared_ptr); - bool has_connections (const std::string&); int reestablish_ports (); int reconnect_ports (); diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index 88c9a09be7..4408da2d25 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -48,6 +48,7 @@ namespace ARDOUR { class TempoMap; class Session; +class AudioEngine; /** * @class Slave @@ -492,7 +493,7 @@ class MIDIClock_Slave : public Slave { class JACK_Slave : public Slave { public: - JACK_Slave (jack_client_t*); + JACK_Slave (AudioEngine&); ~JACK_Slave (); bool speed_and_position (double& speed, framepos_t& pos); @@ -502,11 +503,10 @@ class JACK_Slave : public Slave bool ok() const; framecnt_t resolution () const { return 1; } bool requires_seekahead () const { return false; } - void reset_client (jack_client_t* jack); bool is_always_synced() const { return true; } private: - jack_client_t* jack; + AudioEngine& engine; double speed; bool _starting; }; diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 3d1bf6e77e..05f59707a8 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -103,39 +103,6 @@ AudioEngine::create (const std::string& bcn, const std::string& bsu) return new AudioEngine (bcn, bsu); } -void -AudioEngine::drop_backend () -{ - if (_backend) { - _backend->stop (); - _backend.reset (); - } -} - -int -AudioEngine::set_backend (const std::string& name) -{ - BackendMap::iterator b = _backends.find (name); - - if (b == _backends.end()) { - return -1; - } - - drop_backend (); - - 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; -} - void _thread_init_callback (void * /*arg*/) { @@ -570,6 +537,60 @@ AudioEngine::backend_discover (const string& path) return info; } +vector +AudioEngine::available_backends() const +{ + vector r; + + for (BackendMap::const_iterator i = _backends.begin(); i != _backends.end(); ++i) { + r.push_back (i->first); + } + + return r; +} + +string +AudioEngine::current_backend_name() const +{ + if (_backend) { + return _backend->name(); + } + return string(); +} + +void +AudioEngine::drop_backend () +{ + if (_backend) { + _backend->stop (); + _backend.reset (); + } +} + +int +AudioEngine::set_backend (const std::string& name) +{ + BackendMap::iterator b = _backends.find (name); + + if (b == _backends.end()) { + return -1; + } + + drop_backend (); + + 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; +} + /* BACKEND PROXY WRAPPERS */ int @@ -812,6 +833,89 @@ AudioEngine::create_process_thread (boost::function func, pthread_t* thr } +int +AudioEngine::set_device_name (const std::string& name) +{ + if (!_backend) { + return -1; + } + return _backend->set_device_name (name); +} + +int +AudioEngine::set_sample_rate (float sr) +{ + if (!_backend) { + return -1; + } + return _backend->set_sample_rate (sr); +} + +int +AudioEngine::set_buffer_size (uint32_t bufsiz) +{ + if (!_backend) { + return -1; + } + return _backend->set_buffer_size (bufsiz); +} + +int +AudioEngine::set_sample_format (SampleFormat sf) +{ + if (!_backend) { + return -1; + } + return _backend->set_sample_format (sf); +} + +int +AudioEngine::set_interleaved (bool yn) +{ + if (!_backend) { + return -1; + } + return _backend->set_interleaved (yn); +} + +int +AudioEngine::set_input_channels (uint32_t ic) +{ + if (!_backend) { + return -1; + } + return _backend->set_input_channels (ic); +} + +int +AudioEngine::set_output_channels (uint32_t oc) +{ + if (!_backend) { + return -1; + } + return _backend->set_output_channels (oc); +} + +int +AudioEngine::set_systemic_input_latency (uint32_t il) +{ + if (!_backend) { + return -1; + } + return _backend->set_systemic_input_latency (il); +} + +int +AudioEngine::set_systemic_output_latency (uint32_t ol) +{ + if (!_backend) { + return -1; + } + return _backend->set_systemic_output_latency (ol); +} + +/* END OF BACKEND PROXY API */ + void AudioEngine::thread_init_callback (void* arg) { @@ -873,6 +977,14 @@ AudioEngine::latency_callback (bool for_playback) } } +void +AudioEngine::update_latencies () +{ + if (_backend) { + _backend->update_latencies (); + } +} + void AudioEngine::halted_callback (const char* why) { diff --git a/libs/ardour/bundle.cc b/libs/ardour/bundle.cc index 162db6c793..be4b04e36a 100644 --- a/libs/ardour/bundle.cc +++ b/libs/ardour/bundle.cc @@ -450,6 +450,8 @@ Bundle::connected_to (boost::shared_ptr other, AudioEngine & engine) bool Bundle::connected_to_anything (AudioEngine& engine) { + PortManager& pm (engine); + for (uint32_t i = 0; i < nchannels().n_total(); ++i) { Bundle::PortList const & ports = channel_ports (i); @@ -459,7 +461,7 @@ Bundle::connected_to_anything (AudioEngine& engine) rather than doing it with Port. */ - if (engine.has_connections (ports[j])) { + if (pm.connected (ports[j])) { return true; } } diff --git a/libs/ardour/jack_audiobackend.cc b/libs/ardour/jack_audiobackend.cc index b993135f5a..04ee94a80c 100644 --- a/libs/ardour/jack_audiobackend.cc +++ b/libs/ardour/jack_audiobackend.cc @@ -818,3 +818,10 @@ JACKAudioBackend::cpu_load() const GET_PRIVATE_JACK_POINTER_RET(_priv_jack,0); return jack_cpu_load (_priv_jack); } + +void +JACKAudioBackend::update_latencies () +{ + GET_PRIVATE_JACK_POINTER (_priv_jack); + jack_recompute_total_latencies (_priv_jack); +} diff --git a/libs/ardour/jack_portengine.cc b/libs/ardour/jack_portengine.cc index 4a6f3a1fca..7280c9ff24 100644 --- a/libs/ardour/jack_portengine.cc +++ b/libs/ardour/jack_portengine.cc @@ -1,3 +1,35 @@ +/* + Copyright (C) 2013 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "pbd/failed_constructor.h" + +#include "ardour/jack_portengine.h" +#include "ardour/jack_connection.h" +#include "ardour/port_manager.h" + +using namespace ARDOUR; +using std::string; +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; } @@ -6,13 +38,13 @@ ardour_port_flags_to_jack_flags (PortFlags flags) { uint32_t jack_flags = 0; - if (flags & PortIsInput) { + if (flags & IsInput) { jack_flags |= JackPortIsInput; } - if (flags & IsInput) { + if (flags & IsOutput) { jack_flags |= JackPortIsOutput; } - if (flags & IsOutput) { + if (flags & IsTerminal) { jack_flags |= JackPortIsTerminal; } if (flags & IsPhysical) { @@ -53,17 +85,63 @@ JACKPortEngine::JACKPortEngine (PortManager& pm, boost::shared_ptr + jack_client_t* client = _jack_connection->jack(); - 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); + if (!client) { + throw failed_constructor (); + } + + /* register callbacks for stuff that is our responsibility */ + + jack_set_port_registration_callback (client, _registration_callback, this); + jack_set_port_connect_callback (client, _connect_callback, this); + jack_set_graph_order_callback (client, _graph_order_callback, this); +} + +JACKPortEngine::~JACKPortEngine () +{ + /* a default destructor would do this, and so would this one, + but we'll make it explicit in case we ever need to debug + the lifetime of the JACKConnection + */ + _jack_connection.reset (); +} + +void* +JACKPortEngine::private_handle() const +{ + return _jack_connection->jack(); +} + +int +JACKPortEngine::set_port_name (PortHandle port, const std::string& name) +{ + return jack_port_set_name ((jack_port_t*) port, name.c_str()); +} + +string +JACKPortEngine::get_port_name (PortHandle port) const +{ + return jack_port_name ((jack_port_t*) port); +} + +PortEngine::PortHandle* +JACKPortEngine:: get_port_by_name (const std::string& name) const +{ + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0); + return (PortHandle*) jack_port_by_name (_priv_jack, name.c_str()); } void JACKPortEngine::_registration_callback (jack_port_id_t /*id*/, int /*reg*/, void* arg) { - static_cast (arg)->_manager->registration_callback (); + static_cast (arg)->manager.registration_callback (); +} + +int +JACKPortEngine::_graph_order_callback (void *arg) +{ + return static_cast (arg)->manager.graph_order_callback (); } void @@ -75,7 +153,7 @@ JACKPortEngine::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int void JACKPortEngine::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int conn) { - if (_manager->port_remove_in_progress()) { + if (manager.port_remove_in_progress()) { return; } @@ -84,79 +162,90 @@ JACKPortEngine::connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int jack_port_t* a = jack_port_by_id (_priv_jack, id_a); jack_port_t* b = jack_port_by_id (_priv_jack, id_b); - _manager->connect_callback (jack_port_name (a), jack_port_name (b), conn == 0 ? false : true); + manager.connect_callback (jack_port_name (a), jack_port_name (b), conn == 0 ? false : true); } -int -JACKPortEngine::_graph_order_callback (void *arg) +bool +JACKPortEngine::connected (PortHandle port) { - return static_cast (arg)->graph_order_callback (); -} + bool ret = false; -int -JACKPortEngine::graph_order_callback () -{ - if (_jack_connection->connected()) { - _manager->graph_order_callback (); + const char** ports = jack_port_get_connections ((jack_port_t*) port); + + if (ports) { + ret = true; } - return 0; + jack_free (ports); + + return ret; } +bool +JACKPortEngine::connected_to (PortHandle port, const std::string& other) +{ + bool ret = false; + const char** ports = jack_port_get_connections ((jack_port_t*) port); + + if (ports) { + for (int i = 0; ports[i]; ++i) { + if (other == ports[i]) { + ret = true; + } + } + jack_free (ports); + } + + return ret; +} + +bool JACKPortEngine::physically_connected (PortHandle p) { - jack_port_t* _jack_port = (jack_port_t*) p; + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, false); + jack_port_t* port = (jack_port_t*) p; - const char** jc = jack_port_get_connections (_jack_port); + const char** ports = jack_port_get_connections (port); - if (jc) { - for (int i = 0; jc[i]; ++i) { + if (ports) { + for (int i = 0; ports[i]; ++i) { - jack_port_t* port = jack_port_by_name (_engine->jack(), jc[i]); + jack_port_t* other = jack_port_by_name (_priv_jack, ports[i]); - if (port && (jack_port_flags (port) & JackPortIsPhysical)) { - if (jack_free) { - jack_free (jc); - } else { - free (jc); - } + if (other && (jack_port_flags (other) & JackPortIsPhysical)) { return true; } } - if (jack_free) { - jack_free (jc); - } else { - free (jc); - } + jack_free (ports); } return false; } DataType -JACKPortEngine::port_data_type (PortHandle p) +JACKPortEngine::port_data_type (PortHandle p) const { - return jack_port_type_to_ardour_data_type (jack_port_type (p)); + return jack_port_type_to_ardour_data_type (jack_port_type ((jack_port_t*) p)); } const string& JACKPortEngine::my_name() const { - return _client_name; + return _jack_connection->client_name(); } bool -JACKPortEngine::port_is_physical (PortHandle* ph) const +JACKPortEngine::port_is_physical (PortHandle ph) const { if (!ph) { return false; } - return jack_port_flags (ph) & JackPortIsPhysical; + return jack_port_flags ((jack_port_t*) ph) & JackPortIsPhysical; } int -JACKPortEngine::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector& s) +JACKPortEngine::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector& s) const { GET_PRIVATE_JACK_POINTER_RET (_priv_jack,0); @@ -166,12 +255,11 @@ JACKPortEngine::get_ports (const string& port_name_pattern, DataType type, PortF ardour_port_flags_to_jack_flags (flags)); if (ports == 0) { - return s; + return 0; } for (uint32_t i = 0; ports[i]; ++i) { s.push_back (ports[i]); - jack_free (ports[i]); } jack_free (ports); @@ -184,16 +272,15 @@ JACKPortEngine::n_physical (unsigned long flags) const { ChanCount c; - GET_PRIVATE_JACK_POINTER_RET (_jack, c); + GET_PRIVATE_JACK_POINTER_RET (_priv_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]))); + DataType t (jack_port_type (jack_port_by_name (_priv_jack, ports[i]))); c.set (t, c.get (t) + 1); - jack_free (ports[i]); } } @@ -216,12 +303,12 @@ JACKPortEngine::n_physical_outputs () const } void -JACKPortEngine::get_physical (DataType type, unsigned long flags, vector& phy) +JACKPortEngine::get_physical (DataType type, unsigned long flags, vector& phy) const { GET_PRIVATE_JACK_POINTER (_priv_jack); const char ** ports; - if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) { + if ((ports = jack_get_ports (_priv_jack, NULL, ardour_data_type_to_jack_port_type (type), JackPortIsPhysical | flags)) == 0) { return; } @@ -231,7 +318,6 @@ JACKPortEngine::get_physical (DataType type, unsigned long flags, vector continue; } phy.push_back (ports[i]); - jack_free (ports[i]); } jack_free (ports); } @@ -257,7 +343,7 @@ JACKPortEngine::get_physical_outputs (DataType type, vector& outs) bool -JACKPortEngine::can_request_hardware_monitoring () +JACKPortEngine::can_monitor_input () const { GET_PRIVATE_JACK_POINTER_RET (_priv_jack,false); const char ** ports; @@ -266,18 +352,131 @@ JACKPortEngine::can_request_hardware_monitoring () 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 +pframes_t +JACKPortEngine::sample_time_at_cycle_start () { GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0); return jack_last_frame_time (_priv_jack); } + + +PortEngine::PortHandle +JACKPortEngine::register_port (const std::string& shortname, ARDOUR::DataType type, ARDOUR::PortFlags flags) +{ + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, 0); + return jack_port_register (_priv_jack, shortname.c_str(), + ardour_data_type_to_jack_port_type (type), + ardour_port_flags_to_jack_flags (flags), + 0); +} + +void +JACKPortEngine::unregister_port (PortHandle port) +{ + GET_PRIVATE_JACK_POINTER (_priv_jack); + (void) jack_port_unregister (_priv_jack, (jack_port_t*) port); +} + +int +JACKPortEngine::connect (PortHandle port, const std::string& other) +{ + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); + return jack_connect (_priv_jack, jack_port_name ((jack_port_t*) port), other.c_str()); +} +int +JACKPortEngine::connect (const std::string& src, const std::string& dst) +{ + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); + return jack_connect (_priv_jack, src.c_str(), dst.c_str()); +} + +int +JACKPortEngine::disconnect (PortHandle port, const std::string& other) +{ + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); + return jack_disconnect (_priv_jack, jack_port_name ((jack_port_t*) port), other.c_str()); +} + +int +JACKPortEngine::disconnect (const std::string& src, const std::string& dst) +{ + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); + return jack_disconnect (_priv_jack, src.c_str(), dst.c_str()); +} + +int +JACKPortEngine::disconnect_all (PortHandle port) +{ + GET_PRIVATE_JACK_POINTER_RET (_priv_jack, -1); + return jack_port_disconnect (_priv_jack, (jack_port_t*) port); +} + + +int +JACKPortEngine::midi_event_get (pframes_t& timestamp, size_t& size, uint8_t** buf, void* port_buffer, uint32_t event_index) +{ + jack_midi_event_t ev; + int ret; + + if ((ret = jack_midi_event_get (&ev, port_buffer, event_index)) == 0) { + timestamp = ev.time; + size = ev.size; + *buf = ev.buffer; + } + + return ret; +} + +int +JACKPortEngine::midi_event_put (void* port_buffer, pframes_t timestamp, const uint8_t* buffer, size_t size) +{ + return jack_midi_event_write (port_buffer, timestamp, buffer, size); +} + +uint32_t +JACKPortEngine::get_midi_event_count (void* port_buffer) +{ + return jack_midi_get_event_count (port_buffer); +} + +void +JACKPortEngine::midi_clear (void* port_buffer) +{ + jack_midi_clear_buffer (port_buffer); +} + +void +JACKPortEngine::set_latency_range (PortHandle port, bool for_playback, LatencyRange r) +{ + jack_latency_range_t range; + + range.min = r.min; + range.max = r.max; + + jack_port_set_latency_range ((jack_port_t*) port, for_playback ? JackPlaybackLatency : JackCaptureLatency, &range); +} + +LatencyRange +JACKPortEngine::get_latency_range (PortHandle port, bool for_playback) +{ + jack_latency_range_t range; + LatencyRange ret; + + jack_port_get_latency_range ((jack_port_t*) port, for_playback ? JackPlaybackLatency : JackCaptureLatency, &range); + + ret.min = range.min; + ret.max = range.max; + + return ret; +} + +void* +JACKPortEngine::get_buffer (PortHandle port, pframes_t nframes) +{ + return jack_port_get_buffer ((jack_port_t*) port, nframes); +} diff --git a/libs/ardour/jack_slave.cc b/libs/ardour/jack_slave.cc index 4c2da4c6c4..4b2f3b1860 100644 --- a/libs/ardour/jack_slave.cc +++ b/libs/ardour/jack_slave.cc @@ -20,16 +20,14 @@ #include #include -#include -#include - +#include "ardour/audioengine.h" #include "ardour/slave.h" using namespace std; using namespace ARDOUR; -JACK_Slave::JACK_Slave (jack_client_t* j) - : jack (j) +JACK_Slave::JACK_Slave (AudioEngine& e) + : engine (e) { double x; framepos_t p; @@ -41,12 +39,6 @@ JACK_Slave::~JACK_Slave () { } -void -JACK_Slave::reset_client (jack_client_t* j) -{ - jack = j; -} - bool JACK_Slave::locked() const { @@ -62,33 +54,26 @@ JACK_Slave::ok() const bool JACK_Slave::speed_and_position (double& sp, framepos_t& position) { - jack_position_t pos; - jack_transport_state_t state; - - state = jack_transport_query (jack, &pos); - - switch (state) { - case JackTransportStopped: + switch (engine.transport_state()) { + case TransportStopped: speed = 0; _starting = false; break; - case JackTransportRolling: + case TransportRolling: speed = 1.0; _starting = false; break; - case JackTransportLooping: + case TransportLooping: speed = 1.0; _starting = false; break; - case JackTransportStarting: + case TransportStarting: _starting = true; // don't adjust speed here, just leave it as it was break; - default: - cerr << "WARNING: Unknown JACK transport state: " << state << endl; } sp = speed; - position = pos.frame; + position = engine.transport_frame(); return true; } diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index 5aa6ad0ae7..571d227711 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -70,10 +70,6 @@ Port::Port (std::string const & n, DataType t, PortFlags f) assert (_name.find_first_of (':') == std::string::npos); - if (!port_engine.connected()) { - throw failed_constructor (); - } - if ((_port_handle = port_engine.register_port (_name, t, _flags)) == 0) { cerr << "Failed to register port \"" << _name << "\", reason is unknown from here\n"; throw failed_constructor (); @@ -124,14 +120,6 @@ Port::disconnect_all () bool Port::connected_to (std::string const & o) const { - if (!port_engine.connected()) { - /* in some senses, this answer isn't the right one all the time, - because we know about our connections and will re-establish - them when we reconnect to the port engine. - */ - return false; - } - return port_engine.connected_to (_port_handle, AudioEngine::instance()->make_port_name_non_relative (o)); } diff --git a/libs/ardour/port_manager.cc b/libs/ardour/port_manager.cc index 9c5eaa998b..b5f280292e 100644 --- a/libs/ardour/port_manager.cc +++ b/libs/ardour/port_manager.cc @@ -127,6 +127,30 @@ PortManager::port_is_physical (const std::string& portname) const return _impl->port_is_physical (ph); } +void +PortManager::get_physical_outputs (DataType type, std::vector& s) +{ + _impl->get_physical_outputs (type, s); +} + +void +PortManager::get_physical_inputs (DataType type, std::vector& s) +{ + _impl->get_physical_inputs (type, s); +} + +ChanCount +PortManager::n_physical_outputs () const +{ + return _impl->n_physical_outputs (); +} + +ChanCount +PortManager::n_physical_inputs () const +{ + return _impl->n_physical_inputs (); +} + /** @param name Full or short name of port * @return Corresponding Port or 0. */ @@ -134,11 +158,6 @@ PortManager::port_is_physical (const std::string& portname) const boost::shared_ptr PortManager::get_port_by_name (const string& portname) { - if (!_impl->connected()) { - fatal << _("get_port_by_name() called before engine was started") << endmsg; - /*NOTREACHED*/ - } - if (!port_is_mine (portname)) { /* not an ardour port */ return boost::shared_ptr (); @@ -254,13 +273,6 @@ PortManager::unregister_port (boost::shared_ptr port) { /* caller must hold process lock */ - if (!_impl->connected()) { - /* probably happening when the engine has been halted by JACK, - in which case, there is nothing we can do here. - */ - return 0; - } - { RCUWriter writer (ports); boost::shared_ptr ps = writer.get_copy (); @@ -295,10 +307,6 @@ PortManager::connect (const string& source, const string& destination) { int ret; - if (!_impl->connected()) { - return -1; - } - string s = make_port_name_non_relative (source); string d = make_port_name_non_relative (destination); @@ -330,10 +338,6 @@ PortManager::disconnect (const string& source, const string& destination) { int ret; - if (!_impl->connected()) { - return -1; - } - string s = make_port_name_non_relative (source); string d = make_port_name_non_relative (destination); @@ -429,3 +433,30 @@ PortManager::registration_callback () PortRegisteredOrUnregistered (); /* EMIT SIGNAL */ } } + +bool +PortManager::can_request_input_monitoring () const +{ + return _impl->can_monitor_input (); +} + +void +PortManager::request_input_monitoring (const string& name, bool yn) const +{ + PortEngine::PortHandle ph = _impl->get_port_by_name (name); + + if (ph) { + _impl->request_input_monitoring (ph, yn); + } +} + +void +PortManager::ensure_input_monitoring (const string& name, bool yn) const +{ + PortEngine::PortHandle ph = _impl->get_port_by_name (name); + + if (ph) { + _impl->ensure_input_monitoring (ph, yn); + } +} + diff --git a/libs/ardour/route.cc b/libs/ardour/route.cc index c2965a4617..eabfbaacc0 100644 --- a/libs/ardour/route.cc +++ b/libs/ardour/route.cc @@ -967,7 +967,7 @@ Route::add_processor (boost::shared_ptr processor, boost::shared_ptr< DEBUG_TRACE (DEBUG::Processors, string_compose ( "%1 adding processor %2\n", name(), processor->name())); - if (!AudioEngine::instance()->port_engine().connected() || !processor) { + if (!AudioEngine::instance()->connected() || !processor) { return 1; } @@ -1132,7 +1132,7 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr loc = _processors.end (); } - if (!_session.engine().port_engine().connected()) { + if (!_session.engine().connected()) { return 1; } @@ -1329,7 +1329,7 @@ Route::ab_plugins (bool forward) void Route::clear_processors (Placement p) { - if (!_session.engine().port_engine().connected()) { + if (!_session.engine().connected()) { return; } @@ -1416,7 +1416,7 @@ Route::remove_processor (boost::shared_ptr processor, ProcessorStream return 0; } - if (!_session.engine().port_engine().connected()) { + if (!_session.engine().connected()) { return 1; } @@ -1508,7 +1508,7 @@ Route::remove_processors (const ProcessorList& to_be_deleted, ProcessorStreams* { ProcessorList deleted; - if (!_session.engine().port_engine().connected()) { + if (!_session.engine().connected()) { return 1; } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 1ea3732e3f..e1634db536 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -170,7 +170,7 @@ Session::Session (AudioEngine &eng, interpolation.add_channel_to (0, 0); - if (!eng.port_engine().connected()) { + if (!eng.connected()) { throw failed_constructor(); } @@ -4677,7 +4677,7 @@ Session::set_worst_playback_latency () _worst_output_latency = 0; - if (!_engine.port_engine().connected()) { + if (!_engine.connected()) { return; } @@ -4699,7 +4699,7 @@ Session::set_worst_capture_latency () _worst_input_latency = 0; - if (!_engine.port_engine().connected()) { + if (!_engine.connected()) { return; } diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index 02bf48a0d6..0db4fc33bb 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -147,7 +147,7 @@ Session::start_audio_export (framepos_t position) /* we are ready to go ... */ - if (!_engine.port_engine().connected()) { + if (!_engine.connected()) { return -1; } diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index aa0c90204d..cae3b9720a 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -765,7 +765,7 @@ Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot return 1; } - if (!_engine.port_engine().connected ()) { + if (!_engine.connected ()) { error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"), PROGRAM_NAME) << endmsg; diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index fea2fcd96a..0b0351f506 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -44,7 +44,6 @@ #include "ardour/session.h" #include "ardour/slave.h" #include "ardour/operations.h" -#include "ardour/jack_portengine.h" #include "i18n.h" @@ -1417,13 +1416,6 @@ Session::switch_to_sync_source (SyncSource src) break; case JACK: - /* if we are not using JACK as the port engine, we can't do - * this - */ - if (dynamic_cast(&AudioEngine::instance()->port_engine())) { - return; - } - if (_slave && dynamic_cast(_slave)) { return; } @@ -1432,7 +1424,7 @@ Session::switch_to_sync_source (SyncSource src) return; } - new_slave = new JACK_Slave ((jack_client_t*) AudioEngine::instance()->port_engine().private_handle()); + new_slave = new JACK_Slave (*AudioEngine::instance()); break; default: @@ -1622,16 +1614,6 @@ Session::allow_auto_play (bool yn) auto_play_legal = yn; } -void -Session::reset_jack_connection (jack_client_t* jack) -{ - JACK_Slave* js; - - if (_slave && ((js = dynamic_cast (_slave)) != 0)) { - js->reset_client (jack); - } -} - bool Session::maybe_stop (framepos_t limit) { diff --git a/libs/ardour/wscript b/libs/ardour/wscript index 48cfda7bc2..07bb10f08d 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -43,6 +43,7 @@ libardour_sources = [ 'automation_control.cc', 'automation_list.cc', 'automation_watch.cc', + 'backend_search_path.cc', 'beats_frames_converter.cc', 'broadcast_info.cc', 'buffer.cc', @@ -439,7 +440,8 @@ def build(bld): source = [ 'jack_api.cc', 'jack_connection.cc', - 'jack_audiobackend.cc' + 'jack_audiobackend.cc', + 'jack_portengine.cc' ]) obj.cxxflags = [ '-fPIC' ] obj.name = 'jack_audiobackend' diff --git a/libs/midi++2/jack_midi_port.cc b/libs/midi++2/jack_midi_port.cc index 372a7891c9..8ba27759bc 100644 --- a/libs/midi++2/jack_midi_port.cc +++ b/libs/midi++2/jack_midi_port.cc @@ -155,7 +155,7 @@ JackMIDIPort::cycle_start (pframes_t nframes) pframes_t time; size_t size; uint8_t* buf; - timestamp_t cycle_start_frame = _port_engine.last_frame_time (); + timestamp_t cycle_start_frame = _port_engine.sample_time_at_cycle_start (); for (pframes_t i = 0; i < event_count; ++i) { _port_engine.midi_event_get (time, size, &buf, buffer, i);