diff options
43 files changed, 854 insertions, 841 deletions
diff --git a/libs/ardour/ardour/audio_backend.h b/libs/ardour/ardour/audio_backend.h index 98f6c4d8a7..7ae48c4c46 100644 --- a/libs/ardour/ardour/audio_backend.h +++ b/libs/ardour/ardour/audio_backend.h @@ -33,16 +33,16 @@ class AudioEngine; class AudioBackend { public: - enum State { - Stopped = 0x1, - Running = 0x2, - Paused = 0x4, - Freewheeling = 0x8, - }; - - AudioBackend (AudioEngine& e) : engine (e), _state (Stopped) {} + AudioBackend (AudioEngine& e) : engine (e){} virtual ~AudioBackend () {} + /** Return the name of this backend. + * + * Should use a well-known, unique term. Expected examples + * might include "JACK", "CoreAudio", "ASIO" etc. + */ + virtual std::string name() const = 0; + /** 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. @@ -261,7 +261,7 @@ class AudioBackend { virtual TransportState transport_state () { return TransportStopped; } /** Attempt to locate the transport to @param pos */ - virtual void transport_locate (framepos_t pos) {} + virtual void transport_locate (framepos_t /*pos*/) {} /** Return the current transport location, in samples measured * from the origin (defined by the transport time master) */ @@ -275,11 +275,11 @@ class AudioBackend { * JACK is the only currently known audio API with the concept of a shared * transport timebase. */ - virtual int set_time_master (bool yn) { return 0; } + virtual int set_time_master (bool /*yn*/) { return 0; } virtual framecnt_t sample_rate () const; virtual pframes_t samples_per_cycle () const; - virtual int usecs_per_cycle () const { return _usecs_per_cycle; } + virtual int usecs_per_cycle () const { return 1000000 * (samples_per_cycle() / sample_rate()); } virtual size_t raw_buffer_size (DataType t); /* Process time */ @@ -326,7 +326,7 @@ class AudioBackend { * Can ONLY be called from within a process() callback tree (which implies * that it can only be called by a process thread) */ - virtual bool get_sync_offset (pframes_t& offset) const { return 0; } + virtual bool get_sync_offset (pframes_t& /*offset*/) const { return false; } /** Create a new thread suitable for running part of the buffer process * cycle (i.e. Realtime scheduling, memory allocation, etc. etc are all @@ -338,17 +338,6 @@ class AudioBackend { private: AudioEngine& engine; - State _state; - - std::string _target_device; - float _target_sample_rate; - uint32_t _target_buffer_size; - SampleFormat _target_sample_format; - bool _target_interleaved; - uint32_t _target_input_channels; - uint32_t _target_output_channels; - uin32_t _target_systemic_input_latency; - uin32_t _target_systemic_input_latency; }; } diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h index cbc6b93fe0..21efc5c20c 100644 --- a/libs/ardour/ardour/audio_diskstream.h +++ b/libs/ardour/ardour/audio_diskstream.h @@ -114,7 +114,7 @@ class AudioDiskstream : public Diskstream XMLNode& get_state(void); int set_state(const XMLNode& node, int version); - void request_jack_monitors_input (bool); + void request_input_monitoring (bool); static void swap_by_ptr (Sample *first, Sample *last) { while (first < last) { @@ -159,7 +159,7 @@ class AudioDiskstream : public Diskstream std::string name; bool is_physical () const; - void request_jack_monitors_input (bool) const; + void request_input_monitoring (bool) const; }; /** Information about one of our channels */ diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h index 7f084a5c85..a473dda418 100644 --- a/libs/ardour/ardour/audio_port.h +++ b/libs/ardour/ardour/audio_port.h @@ -48,7 +48,7 @@ class AudioPort : public Port protected: friend class AudioEngine; - AudioPort (std::string const &, Flags); + AudioPort (std::string const &, PortFlags); /* special access for engine only */ Sample* engine_get_whole_audio_buffer (); diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index a3f16ff376..422e12e9d8 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -47,6 +47,7 @@ #include "ardour/session_handle.h" #include "ardour/types.h" #include "ardour/chan_count.h" +#include "ardour/port_manager.h" #ifdef HAVE_JACK_SESSION #include <jack/session.h> @@ -61,37 +62,60 @@ class Session; class ProcessThread; class AudioBackend; -class AudioEngine : public SessionHandlePtr +class AudioEngine : public SessionHandlePtr, public PortManager { public: - typedef std::map<std::string,boost::shared_ptr<Port> > Ports; - - AudioEngine (std::string client_name, std::string session_uuid); + + static AudioEngine* create (const std::string& client_name, const std::string& session_uuid); + virtual ~AudioEngine (); - static int discover_backends(); + int discover_backends(); std::vector<std::string> available_backends() const; std::string current_backend_name () const; + int set_backend (const std::string&); ProcessThread* main_thread() const { return _main_thread; } std::string client_name() const { return backend_client_name; } - - int stop (bool forever = false); - int start (); - int pause (); - int freewheel (bool onoff); + + /* START BACKEND PROXY API + * + * See audio_backend.h for full documentation and semantics. These wrappers + * just forward to a backend implementation. + */ + + int start (); + int stop (); + int pause (); + int freewheel (bool start_stop); + float get_cpu_load() const ; + void transport_start (); + void transport_stop (); + TransportState transport_state (); + void transport_locate (framepos_t pos); + framepos_t transport_frame(); + framecnt_t sample_rate () const; + pframes_t samples_per_cycle () const; + int usecs_per_cycle () const; + size_t raw_buffer_size (DataType t); + pframes_t sample_time (); + pframes_t sample_time_at_cycle_start (); + pframes_t samples_since_cycle_start (); + bool get_sync_offset (pframes_t& offset) const; + int create_process_thread (boost::function<void()> func, pthread_t*, size_t stacksize); + + /* END BACKEND PROXY API */ + bool freewheeling() const { return _freewheeling; } - bool running() const { return _running; } + Glib::Threads::Mutex& process_lock() { return _process_lock; } int request_buffer_size (pframes_t); framecnt_t processed_frames() const { return _processed_frames; } - float get_cpu_load(); - void set_session (Session *); void remove_session (); // not a replacement for SessionHandle::session_going_away() @@ -161,8 +185,11 @@ public: int process_callback (pframes_t nframes); private: + AudioEngine (const std::string& client_name, const std::string& session_uuid); + static AudioEngine* _instance; - + + AudioBackend* _backend; Glib::Threads::Mutex _process_lock; Glib::Threads::Cond session_removed; bool session_remove_pending; @@ -187,6 +214,8 @@ public: Glib::Threads::Thread* m_meter_thread; ProcessThread* _main_thread; + std::string backend_client_name; + std::string backend_session_uuid; void meter_thread (); void start_metering_thread (); @@ -196,6 +225,11 @@ public: void parameter_changed (const std::string&); PBD::ScopedConnection config_connection; + + typedef std::map<std::string,AudioBackend*> BackendMap; + BackendMap _backends; + AudioBackend* backend_discover (const std::string&); + void drop_backend (); }; } // namespace ARDOUR diff --git a/libs/ardour/ardour/backend_search_path.h b/libs/ardour/ardour/backend_search_path.h new file mode 100644 index 0000000000..2adc22bd6f --- /dev/null +++ b/libs/ardour/ardour/backend_search_path.h @@ -0,0 +1,39 @@ +/* + Copyright (C) 2011 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. +*/ + +#ifndef __ardour_backend_search_path_h__ +#define __ardour_backend_search_path_h__ + +#include "pbd/search_path.h" + +namespace ARDOUR { + + /** + * return a SearchPath containing directories in which to look for + * backend plugins. + * + * If ARDOUR_BACKEND_PATH is defined then the SearchPath returned + * will contain only those directories specified in it, otherwise it will + * contain the user and system directories which may contain audio/MIDI + * backends. + */ + PBD::SearchPath backend_search_path (); + +} // namespace ARDOUR + +#endif /* __ardour_backend_search_path_h__ */ diff --git a/libs/ardour/ardour/data_type.h b/libs/ardour/ardour/data_type.h index 6a016ae75a..b4129e2629 100644 --- a/libs/ardour/ardour/data_type.h +++ b/libs/ardour/ardour/data_type.h @@ -21,11 +21,11 @@ #define __ardour_data_type_h__ #include <string> -#include <jack/jack.h> +#include <stdint.h> +#include <glib.h> namespace ARDOUR { - /** A type of Data Ardour is capable of processing. * * The majority of this class is dedicated to conversion to and from various @@ -61,33 +61,25 @@ public: /** Construct from a string (Used for loading from XML and Ports) * The string can be as in an XML file (eg "audio" or "midi"), or a - * Jack type string (from jack_port_type) */ + */ DataType(const std::string& str) : _symbol(NIL) { - if (str == "audio" || str == JACK_DEFAULT_AUDIO_TYPE) + if (!g_ascii_strncasecmp(str.c_str(), "audio", str.length())) { _symbol = AUDIO; - else if (str == "midi" || str == JACK_DEFAULT_MIDI_TYPE) + } else if (!g_ascii_strncasecmp(str.c_str(), "midi", str.length())) { _symbol = MIDI; - } - - /** Get the Jack type this DataType corresponds to */ - const char* to_jack_type() const { - switch (_symbol) { - case AUDIO: return JACK_DEFAULT_AUDIO_TYPE; - case MIDI: return JACK_DEFAULT_MIDI_TYPE; - default: return ""; } } /** Inverse of the from-string constructor */ const char* to_string() const { switch (_symbol) { - case AUDIO: return "audio"; - case MIDI: return "midi"; - default: return "unknown"; // reeeally shouldn't ever happen + case AUDIO: return "audio"; + case MIDI: return "midi"; + default: return "unknown"; // reeeally shouldn't ever happen } } - + const char* to_i18n_string () const; inline operator uint32_t() const { return (uint32_t)_symbol; } @@ -125,7 +117,6 @@ private: }; - } // namespace ARDOUR #endif // __ardour_data_type_h__ diff --git a/libs/ardour/ardour/directory_names.h b/libs/ardour/ardour/directory_names.h index 9f7c778d33..935cdd977b 100644 --- a/libs/ardour/ardour/directory_names.h +++ b/libs/ardour/ardour/directory_names.h @@ -38,6 +38,7 @@ extern const char* const route_templates_dir_name; extern const char* const surfaces_dir_name; extern const char* const user_config_dir_name; extern const char* const panner_dir_name; +extern const char* const backend_dir_name; }; diff --git a/libs/ardour/ardour/jack_audiobackend.h b/libs/ardour/ardour/jack_audiobackend.h index 07214ee77a..2e12d521cd 100644 --- a/libs/ardour/ardour/jack_audiobackend.h +++ b/libs/ardour/ardour/jack_audiobackend.h @@ -93,6 +93,18 @@ ifdef HAVE_JACK_SESSION ChanCount n_physical (unsigned long) const; void get_physical (DataType, unsigned long, std::vector<std::string> &); + + /* pffooo */ + + std::string _target_device; + float _target_sample_rate; + uint32_t _target_buffer_size; + SampleFormat _target_sample_format; + bool _target_interleaved; + uint32_t _target_input_channels; + uint32_t _target_output_channels; + uin32_t _target_systemic_input_latency; + uin32_t _target_systemic_input_latency; }; } diff --git a/libs/ardour/ardour/midi_buffer.h b/libs/ardour/ardour/midi_buffer.h index 5ef5e4c845..781396a598 100644 --- a/libs/ardour/ardour/midi_buffer.h +++ b/libs/ardour/ardour/midi_buffer.h @@ -44,7 +44,6 @@ public: void copy(const MidiBuffer& copy); bool push_back(const Evoral::MIDIEvent<TimeType>& event); - bool push_back(const jack_midi_event_t& event); bool push_back(TimeType time, size_t size, const uint8_t* data); uint8_t* reserve(TimeType time, size_t size); diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h index 5dc55398cb..e14c7926fb 100644 --- a/libs/ardour/ardour/midi_port.h +++ b/libs/ardour/ardour/midi_port.h @@ -59,7 +59,7 @@ class MidiPort : public Port { protected: friend class AudioEngine; - MidiPort (const std::string& name, Flags); + MidiPort (const std::string& name, PortFlags); private: MidiBuffer* _buffer; diff --git a/libs/ardour/ardour/port.h b/libs/ardour/ardour/port.h index 5afe8e2806..6186ce7748 100644 --- a/libs/ardour/ardour/port.h +++ b/libs/ardour/ardour/port.h @@ -30,6 +30,7 @@ #include "pbd/signals.h" #include "ardour/data_type.h" +#include "ardour/port_engine.h" #include "ardour/types.h" namespace ARDOUR { @@ -40,11 +41,6 @@ class Buffer; class Port : public boost::noncopyable { public: - enum Flags { - IsInput = JackPortIsInput, - IsOutput = JackPortIsOutput, - }; - virtual ~Port (); static void set_connecting_blocked( bool yn ) { @@ -62,7 +58,7 @@ public: int set_name (std::string const &); /** @return flags */ - Flags flags () const { + PortFlags flags () const { return _flags; } @@ -90,8 +86,8 @@ public: virtual int connect (Port *); int disconnect (Port *); - void request_monitor_input (bool); - void ensure_monitor_input (bool); + void request_input_monitoring (bool); + void ensure_input_monitoring (bool); bool monitoring_input () const; int reestablish (); int reconnect (); @@ -99,7 +95,7 @@ public: bool last_monitor() const { return _last_monitor; } void set_last_monitor (bool yn) { _last_monitor = yn; } - jack_port_t* jack_port() const { return _jack_port; } + PortEngine::PortHandle port_handle() { return _port_handle; } void get_connected_latency_range (jack_latency_range_t& range, bool playback) const; @@ -122,8 +118,6 @@ public: bool physically_connected () const; - static void set_engine (AudioEngine *); - PBD::Signal1<void,bool> MonitorInputChanged; static PBD::Signal2<void,boost::shared_ptr<Port>,boost::shared_ptr<Port> > PostDisconnect; static PBD::Signal0<void> PortDrop; @@ -143,9 +137,9 @@ public: protected: - Port (std::string const &, DataType, Flags); + Port (std::string const &, DataType, PortFlags); - jack_port_t* _jack_port; ///< JACK port + PortEngine::PortHandle _port_handle; static bool _connecting_blocked; static pframes_t _global_port_buffer_offset; /* access only from process() tree */ @@ -156,15 +150,13 @@ protected: jack_latency_range_t _private_playback_latency; jack_latency_range_t _private_capture_latency; - static AudioEngine* _engine; ///< the AudioEngine - private: std::string _name; ///< port short name - Flags _flags; ///< flags + PortFlags _flags; ///< flags bool _last_monitor; /** ports that we are connected to, kept so that we can - reconnect to JACK when required + reconnect to the backend when required */ std::set<std::string> _connections; diff --git a/libs/ardour/ardour/port_engine.h b/libs/ardour/ardour/port_engine.h new file mode 100644 index 0000000000..3bea32620e --- /dev/null +++ b/libs/ardour/ardour/port_engine.h @@ -0,0 +1,139 @@ +/* + 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. + +*/ + +#ifndef __libardour_port_engine_h__ +#define __libardour_port_engine_h__ + +#include <vector> +#include <string> + +#include <stdint.h> + +#include "ardour/data_type.h" +#include "ardour/types.h" + +namespace ARDOUR { + +/** PortEngine is an abstract base class that defines the functionality + * required by Ardour. + * + * A Port is basically an endpoint for a datastream (which can either be + * continuous, like audio, or event-based, like MIDI). Ports have buffers + * associated with them into which data can be written (if they are output + * ports) and from which data can be read (if they input ports). Ports can be + * connected together so that data written to an output port can be read from + * an input port. These connections can be 1:1, 1:N OR N:1. + * + * Ports may be associated with software only, or with hardware. Hardware + * related ports are often referred to as physical, and correspond to some + * relevant physical entity on a hardware device, such as an audio jack or a + * MIDI connector. Physical ports may be potentially asked to monitor their + * inputs, though some implementations may not support this. + * + * Most physical ports will also be considered "terminal", which means that + * data delivered there or read from there will go to or comes from a system + * outside of the PortEngine implementation's control (e.g. the analog domain + * for audio, or external MIDI devices for MIDI). Non-physical ports can also + * be considered "terminal". For example, the output port of a software + * synthesizer is a terminal port, because the data contained in its buffer + * does not and cannot be considered to come from any other port - it is + * synthesized by its owner. + * + * Ports also have latency associated with them. Each port has a playback + * latency and a capture latency: + * + * <b>capture latency</b>: how long since the data read from the buffer of a + * port arrived at at a terminal port. The data will have + * come from the "outside world" if the terminal port is also + * physical, or will have been synthesized by the entity that + * owns the terminal port. + * + * <b>playback latency</b>: how long until the data written to the buffer of + * port will reach a terminal port. + * + * + * For more detailed questions about the PortEngine API, consult the JACK API + * documentation, on which this entire object is based. + */ + +class PortEngine { + public: + PortEngine() {} + virtual ~PortEngine(); + + /* We use void* here so that the API can be defined for any implementation. + * + * We could theoretically use a template (PortEngine<T>) and define + * PortHandle as T, but this complicates the desired inheritance + * pattern in which FooPortEngine handles things for the Foo API, + * rather than being a derivative of PortEngine<Foo>. + */ + + typedef void* PortHandle; + + virtual bool connected() 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; + + virtual PortHandle register_port (const std::string&, DataType::Symbol, ARDOUR::PortFlags) = 0; + virtual void unregister_port (PortHandle) = 0; + virtual bool connected (PortHandle) = 0; + virtual int disconnect_all (PortHandle) = 0; + virtual bool connected_to (PortHandle, const std::string&) = 0; + virtual int get_connections (PortHandle, std::vector<std::string>&) = 0; + virtual bool physically_connected (PortHandle) = 0; + virtual int connect (PortHandle, const std::string&) = 0; + virtual int disconnect (PortHandle, const std::string&) = 0; + + /* 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_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); + + /* Monitoring */ + + virtual bool can_monitor_input() const = 0; + virtual int request_input_monitoring (PortHandle, bool) = 0; + virtual int ensure_input_monitoring (PortHandle, bool) = 0; + virtual bool monitoring_input (PortHandle) = 0; + + /* Latency management + */ + + struct LatencyRange { + uint32_t min; + uint32_t max; + }; + + virtual void set_latency_range (PortHandle, int dir, LatencyRange) = 0; + virtual LatencyRange get_latency_range (PortHandle, int dir) = 0; + virtual LatencyRange get_connected_latency_range (PortHandle, int dir) = 0; + + virtual void* get_buffer (PortHandle, pframes_t) = 0; + + virtual pframes_t last_frame_time () const = 0; +}; + +} + +#endif /* __libardour_port_engine_h__ */ diff --git a/libs/ardour/ardour/port_manager.h b/libs/ardour/ardour/port_manager.h index f6aedc02a1..399ab46b34 100644 --- a/libs/ardour/ardour/port_manager.h +++ b/libs/ardour/ardour/port_manager.h @@ -32,11 +32,11 @@ #include "pbd/rcu.h" #include "ardour/chan_count.h" +#include "ardour/port.h" +#include "ardour/port_engine.h" namespace ARDOUR { -class Port; - class PortManager { public: @@ -44,36 +44,44 @@ class PortManager PortManager(); virtual ~PortManager() {} + + PortEngine& port_engine() { return *_impl; } /* Port registration */ - virtual boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname) = 0; - virtual boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname) = 0; - virtual int unregister_port (boost::shared_ptr<Port>) = 0; + boost::shared_ptr<Port> register_input_port (DataType, const std::string& portname); + boost::shared_ptr<Port> register_output_port (DataType, const std::string& portname); + int unregister_port (boost::shared_ptr<Port>); /* Port connectivity */ - virtual int connect (const std::string& source, const std::string& destination) = 0; - virtual int disconnect (const std::string& source, const std::string& destination) = 0; - virtual int disconnect (boost::shared_ptr<Port>) = 0; - + 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<Port>); + bool connected (const std::string&); + /* other Port management */ - virtual bool port_is_physical (const std::string&) const = 0; - virtual void get_physical_outputs (DataType type, std::vector<std::string>&) = 0; - virtual void get_physical_inputs (DataType type, std::vector<std::string>&) = 0; - virtual boost::shared_ptr<Port> get_port_by_name (const std::string &) = 0; - virtual void port_renamed (const std::string&, const std::string&) = 0; - virtual ChanCount n_physical_outputs () const = 0; - virtual ChanCount n_physical_inputs () const = 0; - virtual const char ** get_ports (const std::string& port_name_pattern, const std::string& type_name_pattern, uint32_t flags) = 0; + bool port_is_physical (const std::string&) const; + void get_physical_outputs (DataType type, std::vector<std::string>&); + void get_physical_inputs (DataType type, std::vector<std::string>&); + boost::shared_ptr<Port> get_port_by_name (const std::string &); + void port_renamed (const std::string&, const std::string&); + ChanCount n_physical_outputs () const; + ChanCount n_physical_inputs () const; + const char ** get_ports (const std::string& port_name_pattern, const std::string& type_name_pattern, uint32_t flags); void remove_all_ports (); /* per-Port monitoring */ - virtual bool can_request_input_monitoring () const = 0; - virtual void request_input_monitoring (const std::string&, bool) const = 0; + bool can_request_input_monitoring () const; + void request_input_monitoring (const std::string&, bool) const; + void ensure_input_monitoring (const std::string&, bool) const; + + std::string make_port_name_relative (const std::string&) const; + std::string make_port_name_non_relative (const std::string&) const; + bool port_is_mine (const std::string&) const; class PortRegistrationFailure : public std::exception { public: @@ -82,23 +90,17 @@ class PortManager ~PortRegistrationFailure () throw () {} - virtual const char *what() const throw () { return reason.c_str(); } + const char *what() const throw () { return reason.c_str(); } private: std::string reason; }; + protected: - typedef void* PortHandle; - PortHandle register (const std::string&, DataType type, Port::Flags); - void unregister (PortHandle); - bool connected (PortHandle); - int disconnect_all (PortHandle); - bool connected_to (PortHandle, const std::string); - int get_connections (PortHandle, std::vector<std::string>&); - - private: + PortEngine* _impl; SerializedRCUManager<Ports> ports; + boost::shared_ptr<Port> register_port (DataType type, const std::string& portname, bool input); void port_registration_failure (const std::string& portname); }; diff --git a/libs/ardour/ardour/types.h b/libs/ardour/ardour/types.h index 11cdb79575..390f1e4fec 100644 --- a/libs/ardour/ardour/types.h +++ b/libs/ardour/ardour/types.h @@ -584,6 +584,25 @@ namespace ARDOUR { FadeSymmetric, }; + enum TransportState { + /* these values happen to match the constants used by JACK but + this equality cannot be assumed. + */ + TransportStopped = 0, + TransportRolling = 1, + TransportLooping = 2, + TransportStarting = 3, + }; + + enum PortFlags { + /* these values happen to match the constants used by JACK but + this equality cannot be assumed. + */ + IsInput = 1, + IsOutput = 2, + }; + + } // namespace ARDOUR diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc index c302e06681..5c98271e5f 100644 --- a/libs/ardour/audio_diskstream.cc +++ b/libs/ardour/audio_diskstream.cc @@ -1729,7 +1729,7 @@ AudioDiskstream::prep_record_enable () if (Config->get_monitoring_model() == HardwareMonitoring) { for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - (*chan)->source.request_jack_monitors_input (!(_session.config.get_auto_input() && rolling)); + (*chan)->source.request_input_monitoring (!(_session.config.get_auto_input() && rolling)); capturing_sources.push_back ((*chan)->write_source); (*chan)->write_source->mark_streaming_write_started (); } @@ -1750,7 +1750,7 @@ AudioDiskstream::prep_record_disable () boost::shared_ptr<ChannelList> c = channels.reader(); if (Config->get_monitoring_model() == HardwareMonitoring) { for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - (*chan)->source.request_jack_monitors_input (false); + (*chan)->source.request_input_monitoring (false); } } capturing_sources.clear (); @@ -2016,12 +2016,12 @@ AudioDiskstream::allocate_temporary_buffers () } void -AudioDiskstream::request_jack_monitors_input (bool yn) +AudioDiskstream::request_input_monitoring (bool yn) { boost::shared_ptr<ChannelList> c = channels.reader(); for (ChannelList::iterator chan = c->begin(); chan != c->end(); ++chan) { - (*chan)->source.request_jack_monitors_input (yn); + (*chan)->source.request_input_monitoring (yn); } } @@ -2344,13 +2344,13 @@ AudioDiskstream::ChannelSource::is_physical () const } void -AudioDiskstream::ChannelSource::request_jack_monitors_input (bool yn) const +AudioDiskstream::ChannelSource::request_input_monitoring (bool yn) const { if (name.empty()) { return; } - return AudioEngine::instance()->request_jack_monitors_input (name, yn); + return AudioEngine::instance()->request_input_monitoring (name, yn); } AudioDiskstream::ChannelInfo::ChannelInfo (framecnt_t playback_bufsize, framecnt_t capture_bufsize, framecnt_t speed_size, framecnt_t wrap_size) diff --git a/libs/ardour/audio_port.cc b/libs/ardour/audio_port.cc index 240224ea5e..6a86360b69 100644 --- a/libs/ardour/audio_port.cc +++ b/libs/ardour/audio_port.cc @@ -21,13 +21,17 @@ #include "pbd/stacktrace.h" #include "ardour/audio_buffer.h" +#include "ardour/audioengine.h" #include "ardour/audio_port.h" #include "ardour/data_type.h" +#include "ardour/port_engine.h" using namespace ARDOUR; using namespace std; -AudioPort::AudioPort (const std::string& name, Flags flags) +#define port_engine AudioEngine::instance()->port_engine() + +AudioPort::AudioPort (const std::string& name, PortFlags flags) : Port (name, DataType::AUDIO, flags) , _buffer (new AudioBuffer (0)) { @@ -73,7 +77,7 @@ AudioBuffer& AudioPort::get_audio_buffer (pframes_t nframes) { /* caller must hold process lock */ - _buffer->set_data ((Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes) + + _buffer->set_data ((Sample *) port_engine.get_buffer (_port_handle, _cycle_nframes) + _global_port_buffer_offset + _port_buffer_offset, nframes); return *_buffer; } @@ -82,7 +86,7 @@ Sample* AudioPort::engine_get_whole_audio_buffer () { /* caller must hold process lock */ - return (Sample *) jack_port_get_buffer (_jack_port, _cycle_nframes); + return (Sample *) port_engine.get_buffer (_port_handle, _cycle_nframes); } diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 25a55b5aaf..1e43c590a0 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -25,11 +25,14 @@ #include <sstream> #include <glibmm/timer.h> +#include <glibmm/pattern.h> +#include <glibmm/module.h> +#include "pbd/epa.h" +#include "pbd/file_utils.h" #include "pbd/pthread_utils.h" #include "pbd/stacktrace.h" #include "pbd/unknown_type.h" -#include "pbd/epa.h" #include <jack/weakjack.h> @@ -39,7 +42,9 @@ #include "midi++/manager.h" #include "ardour/audio_port.h" +#include "ardour/audio_backend.h" #include "ardour/audioengine.h" +#include "ardour/backend_search_path.h" #include "ardour/buffer.h" #include "ardour/cycle_timer.h" #include "ardour/internal_send.h" @@ -58,8 +63,9 @@ using namespace PBD; gint AudioEngine::m_meter_exit; AudioEngine* AudioEngine::_instance = 0; -AudioEngine::AudioEngine () - : session_remove_pending (false) +AudioEngine::AudioEngine (const std::string& bcn, const std::string& bsu) + : _backend (0) + , session_remove_pending (false) , session_removal_countdown (-1) , monitor_check_interval (INT32_MAX) , last_monitor_check (0) @@ -70,14 +76,16 @@ AudioEngine::AudioEngine () , port_remove_in_progress (false) , m_meter_thread (0) , _main_thread (0) + , backend_client_name (bcn) + , backend_session_uuid (bsu) { g_atomic_int_set (&m_meter_exit, 0); - - Port::set_engine (this); } AudioEngine::~AudioEngine () { + drop_backend (); + config_connection.disconnect (); { @@ -88,18 +96,38 @@ AudioEngine::~AudioEngine () } AudioEngine* -AudioEngine::create () +AudioEngine::create (const std::string& bcn, const std::string& bsu) { if (_instance) { return _instance; } - return new AudioEngine; + return new AudioEngine (bcn, bsu); } -jack_client_t* -AudioEngine::jack() const +void +AudioEngine::drop_backend () { - return _jack; + if (_backend) { + _backend->stop (); + delete _backend; + _backend = 0; + } +} + +int +AudioEngine::set_backend (const std::string& name) +{ + BackendMap::iterator b = _backends.find (name); + + if (b == _backends.end()) { + return -1; + } + + drop_backend (); + + _backend = b->second; + + return 0; } void @@ -120,70 +148,6 @@ _thread_init_callback (void * /*arg*/) } -int -AudioEngine::start () -{ - GET_PRIVATE_JACK_POINTER_RET (_jack, -1); - - if (!_running) { - - if (!jack_port_type_get_buffer_size) { - warning << _("This version of JACK is old - you should upgrade to a newer version that supports jack_port_type_get_buffer_size()") << endmsg; - } - - if (_session) { - BootMessage (_("Connect session to engine")); - _session->set_frame_rate (jack_get_sample_rate (_priv_jack)); - } - - /* a proxy for whether jack_activate() will definitely call the buffer size - * callback. with older versions of JACK, this function symbol will be null. - * this is reliable, but not clean. - */ - - if (!jack_port_type_get_buffer_size) { - jack_bufsize_callback (jack_get_buffer_size (_priv_jack)); - } - - _processed_frames = 0; - last_monitor_check = 0; - - set_jack_callbacks (); - - if (jack_activate (_priv_jack) == 0) { - _running = true; - _has_run = true; - Running(); /* EMIT SIGNAL */ - } else { - // error << _("cannot activate JACK client") << endmsg; - } - } - - return _running ? 0 : -1; -} - -int -AudioEngine::stop (bool forever) -{ - GET_PRIVATE_JACK_POINTER_RET (_jack, -1); - - if (_priv_jack) { - if (forever) { - disconnect_from_jack (); - } else { - jack_deactivate (_priv_jack); - MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */ - Stopped(); /* EMIT SIGNAL */ - } - } - - if (forever) { - stop_metering_thread (); - } - - return _running ? -1 : 0; -} - void AudioEngine::split_cycle (pframes_t offset) @@ -208,7 +172,6 @@ AudioEngine::split_cycle (pframes_t offset) int AudioEngine::process_callback (pframes_t nframes) { - GET_PRIVATE_JACK_POINTER_RET(_jack,0); Glib::Threads::Mutex::Lock tm (_process_lock, Glib::Threads::TRY_LOCK); PT_TIMING_REF; @@ -436,7 +399,7 @@ AudioEngine::set_session (Session *s) start_metering_thread (); - pframes_t blocksize = jack_get_buffer_size (_jack); + pframes_t blocksize = _backend->get_buffer_size (); /* page in as much of the session process code as we can before we really start running. @@ -484,549 +447,290 @@ AudioEngine::remove_session () remove_all_ports (); } + void -AudioEngine::port_registration_failure (const std::string& portname) +AudioEngine::died () { - GET_PRIVATE_JACK_POINTER (_jack); - string full_portname = jack_client_name; - full_portname += ':'; - full_portname += portname; - - - jack_port_t* p = jack_port_by_name (_priv_jack, full_portname.c_str()); - string reason; + /* called from a signal handler for SIGPIPE */ - 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); - } + stop_metering_thread (); - throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str()); + _running = false; + _buffer_size = 0; + _frame_rate = 0; } -boost::shared_ptr<Port> -AudioEngine::register_port (DataType dtype, const string& portname, bool input) +int +AudioEngine::reset_timebase () { - boost::shared_ptr<Port> newport; - - try { - if (dtype == DataType::AUDIO) { - newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput))); - } else if (dtype == DataType::MIDI) { - newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput))); + if (_session) { + if (_session->config.get_jack_time_master()) { + _backend->set_time_master (true); } else { - throw PortRegistrationFailure("unable to create port (unknown type)"); + _backend->set_time_master (false); } - - RCUWriter<Ports> writer (ports); - boost::shared_ptr<Ports> ps = writer.get_copy (); - ps->insert (make_pair (make_port_name_relative (portname), newport)); - - /* writer goes out of scope, forces update */ - - return newport; - } - - catch (PortRegistrationFailure& err) { - throw err; - } catch (std::exception& e) { - throw PortRegistrationFailure(string_compose( - _("unable to create port: %1"), e.what()).c_str()); - } catch (...) { - throw PortRegistrationFailure("unable to create port (unknown error)"); } + return 0; } -boost::shared_ptr<Port> -AudioEngine::register_input_port (DataType type, const string& portname) -{ - return register_port (type, portname, true); -} -boost::shared_ptr<Port> -AudioEngine::register_output_port (DataType type, const string& portname) +void +AudioEngine::destroy () { - return register_port (type, portname, false); + delete _instance; + _instance = 0; } int -AudioEngine::unregister_port (boost::shared_ptr<Port> port) +AudioEngine::discover_backends () { - /* caller must hold process lock */ - - if (!_running) { - /* probably happening when the engine has been halted by JACK, - in which case, there is nothing we can do here. - */ - return 0; - } - - { - RCUWriter<Ports> writer (ports); - boost::shared_ptr<Ports> ps = writer.get_copy (); - Ports::iterator x = ps->find (make_port_name_relative (port->name())); + vector<std::string> backend_modules; + AudioBackend* backend; - if (x != ps->end()) { - ps->erase (x); - } + _backends.clear (); - /* writer goes out of scope, forces update */ - } + Glib::PatternSpec so_extension_pattern("*.so"); + Glib::PatternSpec dylib_extension_pattern("*.dylib"); - ports.flush (); + find_matching_files_in_search_path (backend_search_path (), + so_extension_pattern, backend_modules); - return 0; -} + find_matching_files_in_search_path (backend_search_path (), + dylib_extension_pattern, backend_modules); -int -AudioEngine::connect (const string& source, const string& destination) -{ - int ret; + DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1"), backend_search_path().to_string())); - if (!_running) { - if (!_has_run) { - fatal << _("connect called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - return -1; + for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) { + if ((backend = backend_discover (*i)) != 0) { + _backends.insert (make_pair (backend->name(), backend)); } } - string s = make_port_name_non_relative (source); - string d = make_port_name_non_relative (destination); - + return _backends.size(); +} - boost::shared_ptr<Port> src = get_port_by_name (s); - boost::shared_ptr<Port> dst = get_port_by_name (d); +AudioBackend* +AudioEngine::backend_discover (const string& path) +{ + Glib::Module* module = new Glib::Module(path); + AudioBackend* (*dfunc)(void); + void* func = 0; - if (src) { - ret = src->connect (d); - } else if (dst) { - ret = dst->connect (s); - } else { - /* neither port is known to us, and this API isn't intended for use as a general patch bay */ - ret = -1; + if (!module) { + error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path, + Glib::Module::get_last_error()) << endmsg; + delete module; + return 0; } - if (ret > 0) { - /* already exists - no error, no warning */ - } else if (ret < 0) { - error << string_compose(_("AudioEngine: cannot connect %1 (%2) to %3 (%4)"), - source, s, destination, d) - << endmsg; + if (!module->get_symbol("backend_factory", func)) { + error << string_compose(_("AudioEngine: module \"%1\" has no factory function."), path) << endmsg; + error << Glib::Module::get_last_error() << endmsg; + delete module; + return 0; } - return ret; + dfunc = (AudioBackend* (*)(void))func; + AudioBackend* backend = dfunc(); + + return backend; } +/* BACKEND PROXY WRAPPERS */ + int -AudioEngine::disconnect (const string& source, const string& destination) +AudioEngine::start () { - int ret; - - if (!_running) { - if (!_has_run) { - fatal << _("disconnect called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - return -1; - } + if (!_backend) { + return -1; } - string s = make_port_name_non_relative (source); - string d = make_port_name_non_relative (destination); - - boost::shared_ptr<Port> src = get_port_by_name (s); - boost::shared_ptr<Port> dst = get_port_by_name (d); + if (!_running) { - if (src) { - ret = src->disconnect (d); - } else if (dst) { - ret = dst->disconnect (s); - } else { - /* neither port is known to us, and this API isn't intended for use as a general patch bay */ - ret = -1; - } - return ret; -} + if (_session) { + BootMessage (_("Connect session to engine")); + _session->set_frame_rate (_backend->sample_rate()); + } -int -AudioEngine::disconnect (boost::shared_ptr<Port> port) -{ - GET_PRIVATE_JACK_POINTER_RET (_jack,-1); + _processed_frames = 0; + last_monitor_check = 0; - if (!_running) { - if (!_has_run) { - fatal << _("disconnect called before engine was started") << endmsg; - /*NOTREACHED*/ + if (_backend->start() == 0) { + _running = true; + _has_run = true; + Running(); /* EMIT SIGNAL */ } else { - return -1; + /* should report error? */ } } - - return port->disconnect_all (); + + return _running ? 0 : -1; } -ARDOUR::framecnt_t -AudioEngine::frame_rate () const +int +AudioEngine::stop () { - GET_PRIVATE_JACK_POINTER_RET (_jack, 0); - if (_frame_rate == 0) { - return (_frame_rate = jack_get_sample_rate (_priv_jack)); - } else { - return _frame_rate; + if (!_backend) { + return 0; } + + return _backend->stop (); } -size_t -AudioEngine::raw_buffer_size (DataType t) -{ - std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t); - return (s != _raw_buffer_sizes.end()) ? s->second : 0; -} - -ARDOUR::pframes_t -AudioEngine::frames_per_cycle () const +int +AudioEngine::pause () { - GET_PRIVATE_JACK_POINTER_RET (_jack,0); - if (_buffer_size == 0) { - return jack_get_buffer_size (_jack); - } else { - return _buffer_size; + if (!_backend) { + return 0; } + + return _backend->pause (); } -/** @param name Full or short name of port - * @return Corresponding Port or 0. - */ - -boost::shared_ptr<Port> -AudioEngine::get_port_by_name (const string& portname) +int +AudioEngine::freewheel (bool start_stop) { - if (!_running) { - if (!_has_run) { - fatal << _("get_port_by_name() called before engine was started") << endmsg; - /*NOTREACHED*/ - } else { - boost::shared_ptr<Port> (); - } + if (!_backend) { + return -1; } - if (!port_is_mine (portname)) { - /* not an ardour port */ - return boost::shared_ptr<Port> (); - } - - boost::shared_ptr<Ports> pr = ports.reader(); - std::string rel = make_port_name_relative (portname); - Ports::iterator x = pr->find (rel); + /* _freewheeling will be set when first Freewheel signal occurs */ - if (x != pr->end()) { - /* its possible that the port was renamed by some 3rd party and - we don't know about it. check for this (the check is quick - 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())); - if (check != rel) { - x->second->set_name (check); - } - return x->second; - } - - return boost::shared_ptr<Port> (); + return _backend->freewheel (start_stop); } -void -AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name) +float +AudioEngine::get_cpu_load() const { - RCUWriter<Ports> writer (ports); - boost::shared_ptr<Ports> p = writer.get_copy(); - Ports::iterator x = p->find (old_relative_name); - - if (x != p->end()) { - boost::shared_ptr<Port> port = x->second; - p->erase (x); - p->insert (make_pair (new_relative_name, port)); + if (!_backend) { + return 0.0; } + return _backend->get_cpu_load (); } -const char ** -AudioEngine::get_ports (const string& port_name_pattern, const string& type_name_pattern, uint32_t flags) +void +AudioEngine::transport_start () { - 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; - } + if (!_backend) { + return; } - return jack_get_ports (_priv_jack, port_name_pattern.c_str(), type_name_pattern.c_str(), flags); + return _backend->transport_start (); } void -AudioEngine::died () -{ - /* called from a signal handler for SIGPIPE */ - - stop_metering_thread (); - - _running = false; - _buffer_size = 0; - _frame_rate = 0; - _jack = 0; -} - -bool -AudioEngine::can_request_hardware_monitoring () +AudioEngine::transport_stop () { - GET_PRIVATE_JACK_POINTER_RET (_jack,false); - const char ** ports; - - if ((ports = jack_get_ports (_priv_jack, NULL, JACK_DEFAULT_AUDIO_TYPE, JackPortCanMonitor)) == 0) { - return false; + if (!_backend) { + return; } - - free (ports); - - return true; + return _backend->transport_stop (); } -ChanCount -AudioEngine::n_physical (unsigned long flags) const +TransportState +AudioEngine::transport_state () { - 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; + if (!_backend) { + return TransportStopped; } - - 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); + return _backend->transport_state (); } void -AudioEngine::get_physical (DataType type, unsigned long flags, vector<string>& phy) +AudioEngine::transport_locate (framepos_t pos) { - GET_PRIVATE_JACK_POINTER (_jack); - const char ** ports; - - if ((ports = jack_get_ports (_priv_jack, NULL, type.to_jack_type(), JackPortIsPhysical | flags)) == 0) { + if (!_backend) { return; } + return _backend->transport_locate (pos); +} - if (ports) { - for (uint32_t i = 0; ports[i]; ++i) { - if (strstr (ports[i], "Midi-Through")) { - continue; - } - phy.push_back (ports[i]); - } - free (ports); +framepos_t +AudioEngine::transport_frame() +{ + if (!_backend) { + return 0; } + return _backend->transport_frame (); } -/** 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<string>& ins) +framecnt_t +AudioEngine::sample_rate () const { - get_physical (type, JackPortIsOutput, ins); + if (!_backend) { + return 0; + } + return _backend->sample_rate (); } -/** 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<string>& outs) +pframes_t +AudioEngine::samples_per_cycle () const { - get_physical (type, JackPortIsInput, outs); + if (!_backend) { + return 0; + } + return _backend->samples_per_cycle (); } - int -AudioEngine::reset_timebase () +AudioEngine::usecs_per_cycle () const { - GET_PRIVATE_JACK_POINTER_RET (_jack, -1); - if (_session) { - if (_session->config.get_jack_time_master()) { - _backend->set_time_master (true); - } else { - _backend->set_time_master (false); - } + if (!_backend) { + return -1; } - return 0; + return _backend->start (); } -void -AudioEngine::remove_all_ports () +size_t +AudioEngine::raw_buffer_size (DataType t) { - /* 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; - - /* process lock MUST be held by caller - */ - - { - RCUWriter<Ports> writer (ports); - boost::shared_ptr<Ports> ps = writer.get_copy (); - ps->clear (); + if (!_backend) { + return -1; } - - /* clear dead wood list in RCU */ - - ports.flush (); - - port_remove_in_progress = false; + return _backend->raw_buffer_size (t); } - -string -AudioEngine::make_port_name_relative (string portname) const +pframes_t +AudioEngine::sample_time () { - string::size_type len; - string::size_type n; - - len = portname.length(); - - for (n = 0; n < len; ++n) { - if (portname[n] == ':') { - break; - } - } - - if ((n != len) && (portname.substr (0, n) == jack_client_name)) { - return portname.substr (n+1); + if (!_backend) { + return 0; } - - return portname; + return _backend->sample_time (); } -string -AudioEngine::make_port_name_non_relative (string portname) const +pframes_t +AudioEngine::sample_time_at_cycle_start () { - string str; - - if (portname.find_first_of (':') != string::npos) { - return portname; + if (!_backend) { + return 0; } - - str = jack_client_name; - str += ':'; - str += portname; - - return str; + return _backend->sample_time_at_cycle_start (); } -bool -AudioEngine::port_is_mine (const string& portname) const +pframes_t +AudioEngine::samples_since_cycle_start () { - if (portname.find_first_of (':') != string::npos) { - if (portname.substr (0, jack_client_name.length ()) != jack_client_name) { - return false; - } - } - return true; + if (!_backend) { + return 0; + } + return _backend->samples_since_cycle_start (); } 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; -} - -void -AudioEngine::destroy () +AudioEngine::get_sync_offset (pframes_t& offset) const { - delete _instance; - _instance = 0; + if (!_backend) { + return false; + } + return _backend->get_sync_offset (offset); } int -AudioEngine::discover_backends () +AudioEngine::create_process_thread (boost::function<void()> func, pthread_t* thr, size_t stacksize) { - vector<std::string> backend_modules; - AudioBackend* backend; - - Glib::PatternSpec so_extension_pattern("*.so"); - Glib::PatternSpec dylib_extension_pattern("*.dylib"); - - find_matching_files_in_search_path (backend_search_path (), - so_extension_pattern, backend_modules); - - find_matching_files_in_search_path (backend_search_path (), - dylib_extension_pattern, backend_modules); - - DEBUG_TRACE (DEBUG::Panning, string_compose (_("looking for backends in %1"), backend_search_path().to_string())); - - for (vector<std::string>::iterator i = backend_modules.begin(); i != backend_modules.end(); ++i) { - if ((backend = backend_discover (*i)) != 0) { - _backends.insert (make_pair (backend->name(), backend)); - } + if (!_backend) { + return -1; } + return _backend->create_process_thread (func, thr, stacksize); } -AudioBackend* -AudioEngine::backend_discover (string path) -{ - Glib::Module* module = new Glib::Module(path); - AudioBackend* (*dfunc)(void); - void* func = 0; - - if (!module) { - error << string_compose(_("AudioEngine: cannot load module \"%1\" (%2)"), path, - Glib::Module::get_last_error()) << endmsg; - delete module; - return 0; - } - - if (!module->get_symbol("backend_factory", func)) { - error << string_compose(_("AudioEngine: module \"%1\" has no factory function."), path) << endmsg; - error << Glib::Module::get_last_error() << endmsg; - delete module; - return 0; - } - - dfunc = (AudioBackend* (*)(void))func; - AudioBackend* backend = dfunc(); - - return backend; -} diff --git a/libs/ardour/backend_search_path.cc b/libs/ardour/backend_search_path.cc new file mode 100644 index 0000000000..9a0425094b --- /dev/null +++ b/libs/ardour/backend_search_path.cc @@ -0,0 +1,45 @@ +/* + 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 <glibmm/miscutils.h> + +#include "ardour/backend_search_path.h" +#include "ardour/directory_names.h" +#include "ardour/filesystem_paths.h" + +namespace { + const char * const backend_env_variable_name = "ARDOUR_BACKEND_PATH"; +} // anonymous + +using namespace PBD; + +namespace ARDOUR { + +SearchPath +backend_search_path () +{ + SearchPath spath(user_config_directory ()); + spath += ardour_dll_directory (); + spath.add_subdirectory_to_paths(backend_dir_name); + + spath += SearchPath(Glib::getenv(backend_env_variable_name)); + return spath; +} + +} // namespace ARDOUR diff --git a/libs/ardour/bundle.cc b/libs/ardour/bundle.cc index 0ac62d7076..9d5640491f 100644 --- a/libs/ardour/bundle.cc +++ b/libs/ardour/bundle.cc @@ -454,16 +454,13 @@ Bundle::connected_to_anything (AudioEngine& engine) Bundle::PortList const & ports = channel_ports (i); for (uint32_t j = 0; j < ports.size(); ++j) { - /* ports[j] may not be an Ardour port, so use JACK directly + + /* ports[j] may not be an Ardour port, so use the port manager directly rather than doing it with Port. */ - jack_port_t* jp = jack_port_by_name (engine.jack(), ports[j].c_str()); - if (jp) { - const char ** c = jack_port_get_all_connections (engine.jack(), jp); - if (c) { - jack_free (c); - return true; - } + + if (engine.connected (ports[j])) { + return true; } } } diff --git a/libs/ardour/capturing_processor.cc b/libs/ardour/capturing_processor.cc index c4b463aba7..f14e018097 100644 --- a/libs/ardour/capturing_processor.cc +++ b/libs/ardour/capturing_processor.cc @@ -28,7 +28,7 @@ namespace ARDOUR { CapturingProcessor::CapturingProcessor (Session & session) : Processor (session, X_("capture point")) - , block_size (session.engine().frames_per_cycle()) + , block_size (AudioEngine::instance()->samples_per_cycle()) { realloc_buffers (); } diff --git a/libs/ardour/directory_names.cc b/libs/ardour/directory_names.cc index 0632c6f8f2..af7f7f550c 100644 --- a/libs/ardour/directory_names.cc +++ b/libs/ardour/directory_names.cc @@ -37,6 +37,7 @@ const char* const templates_dir_name = X_("templates"); const char* const route_templates_dir_name = X_("route_templates"); const char* const surfaces_dir_name = X_("surfaces"); const char* const panner_dir_name = X_("panners"); +const char* const backend_dir_name = X_("backends"); /* these should end up using variants of PROGRAM_NAME */ #ifdef __APPLE__ diff --git a/libs/ardour/export_channel.cc b/libs/ardour/export_channel.cc index 9b3f50e85d..82e5d80244 100644 --- a/libs/ardour/export_channel.cc +++ b/libs/ardour/export_channel.cc @@ -117,7 +117,7 @@ RegionExportChannelFactory::RegionExportChannelFactory (Session * session, Audio : region (region) , track (track) , type (type) - , frames_per_cycle (session->engine().frames_per_cycle ()) + , frames_per_cycle (session->engine().samples_per_cycle ()) , buffers_up_to_date (false) , region_start (region.position()) , position (region_start) diff --git a/libs/ardour/export_graph_builder.cc b/libs/ardour/export_graph_builder.cc index c7875c0b9b..301914b0ae 100644 --- a/libs/ardour/export_graph_builder.cc +++ b/libs/ardour/export_graph_builder.cc @@ -54,7 +54,7 @@ ExportGraphBuilder::ExportGraphBuilder (Session const & session) : session (session) , thread_pool (hardware_concurrency()) { - process_buffer_frames = session.engine().frames_per_cycle(); + process_buffer_frames = session.engine().samples_per_cycle(); } ExportGraphBuilder::~ExportGraphBuilder () @@ -505,7 +505,7 @@ ExportGraphBuilder::ChannelConfig::ChannelConfig (ExportGraphBuilder & parent, F config = new_config; - framecnt_t max_frames = parent.session.engine().frames_per_cycle(); + framecnt_t max_frames = parent.session.engine().samples_per_cycle(); interleaver.reset (new Interleaver<Sample> ()); interleaver->init (new_config.channel_config->get_n_chans(), max_frames); diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 4c91956ffd..b2833db4fa 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -338,7 +338,7 @@ void ARDOUR::init_post_engine () { /* the MIDI Manager is needed by the ControlProtocolManager */ - MIDI::Manager::create (AudioEngine::instance()->jack()); + MIDI::Manager::create (AudioEngine::instance()->port_engine()); ControlProtocolManager::instance().discover_control_protocols (); diff --git a/libs/ardour/internal_send.cc b/libs/ardour/internal_send.cc index 26631d0fad..4b8c469a9d 100644 --- a/libs/ardour/internal_send.cc +++ b/libs/ardour/internal_send.cc @@ -310,7 +310,7 @@ bool InternalSend::configure_io (ChanCount in, ChanCount out) { bool ret = Send::configure_io (in, out); - set_block_size (_session.engine().frames_per_cycle()); + set_block_size (_session.engine().samples_per_cycle()); return ret; } diff --git a/libs/ardour/jack_audiobackend.cc b/libs/ardour/jack_audiobackend.cc index 2d614a80a0..46e270f0ca 100644 --- a/libs/ardour/jack_audiobackend.cc +++ b/libs/ardour/jack_audiobackend.cc @@ -6,12 +6,43 @@ int JACKAudioBackend::start () { - Glib::Threads::Mutex::Lock lm (_state_lock); + GET_PRIVATE_JACK_POINTER_RET (_jack, -1); + + if (!_running) { + + if (!jack_port_type_get_buffer_size) { + warning << _("This version of JACK is old - you should upgrade to a newer version that supports jack_port_type_get_buffer_size()") << endmsg; + } + + if (_session) { + BootMessage (_("Connect session to engine")); + _session->set_frame_rate (jack_get_sample_rate (_priv_jack)); + } + + /* a proxy for whether jack_activate() will definitely call the buffer size + * callback. with older versions of JACK, this function symbol will be null. + * this is reliable, but not clean. + */ + + if (!jack_port_type_get_buffer_size) { + jack_bufsize_callback (jack_get_buffer_size (_priv_jack)); + } + + _processed_frames = 0; + last_monitor_check = 0; - if (running()) { - /* already running */ - return 1; + set_jack_callbacks (); + + if (jack_activate (_priv_jack) == 0) { + _running = true; + _has_run = true; + Running(); /* EMIT SIGNAL */ + } else { + // error << _("cannot activate JACK client") << endmsg; + } } + + return _running ? 0 : -1; } int @@ -70,6 +101,39 @@ JACKAudioBackend::get_parameters (Parameters& params) const return 0; } +/* parameters */ + +ARDOUR::pframes_t +AudioEngine::frames_per_cycle () const +{ + GET_PRIVATE_JACK_POINTER_RET (_jack,0); + if (_buffer_size == 0) { + return jack_get_buffer_size (_jack); + } else { + return _buffer_size; + } +} + +ARDOUR::framecnt_t +AudioEngine::frame_rate () const +{ + GET_PRIVATE_JACK_POINTER_RET (_jack, 0); + if (_frame_rate == 0) { + return (_frame_rate = jack_get_sample_rate (_priv_jack)); + } else { + return _frame_rate; + } +} + +size_t +AudioEngine::raw_buffer_size (DataType t) +{ + std::map<DataType,size_t>::const_iterator s = _raw_buffer_sizes.find(t); + return (s != _raw_buffer_sizes.end()) ? s->second : 0; +} + + + /*--- private support methods ---*/ int @@ -539,8 +603,8 @@ JACKAudioBackend::process_thread () GET_PRIVATE_JACK_POINTER_RET(_jack,0); pframes_t nframes = jack_cycle_wait (_priv_jack); - - if (process_callback (nframes)) { + + if (engine.process_callback (nframes)) { return 0; } diff --git a/libs/ardour/ltc_slave.cc b/libs/ardour/ltc_slave.cc index 8d08fd6bb5..fecab5b606 100644 --- a/libs/ardour/ltc_slave.cc +++ b/libs/ardour/ltc_slave.cc @@ -420,15 +420,15 @@ bool LTC_Slave::speed_and_position (double& speed, framepos_t& pos) { bool engine_init_called = false; - framepos_t now = session.engine().frame_time_at_cycle_start(); + framepos_t now = session.engine().sample_time_at_cycle_start(); framepos_t sess_pos = session.transport_frame(); // corresponds to now - framecnt_t nframes = session.engine().frames_per_cycle(); + framecnt_t nframes = session.engine().samples_per_cycle(); - jack_default_audio_sample_t *in; + Sample* in; boost::shared_ptr<Port> ltcport = session.ltc_input_port(); - in = (jack_default_audio_sample_t*) jack_port_get_buffer (ltcport->jack_port(), nframes); + in = (Sample*) AudioEngine::instance()->port_engine().get_buffer (ltcport->port_handle(), nframes); frameoffset_t skip = now - (monotonic_cnt + nframes); monotonic_cnt = now; @@ -441,7 +441,7 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos) else if (engine_dll_initstate != transport_direction && ltc_speed != 0) { engine_dll_initstate = transport_direction; init_engine_dll(last_ltc_frame + rint(ltc_speed * double(2 * nframes + now - last_timestamp)), - session.engine().frames_per_cycle()); + session.engine().samples_per_cycle()); engine_init_called = true; } @@ -521,8 +521,8 @@ LTC_Slave::speed_and_position (double& speed, framepos_t& pos) t0 = t1; t1 += b * e + e2; e2 += c * e; - speed_flt = (t1 - t0) / double(session.engine().frames_per_cycle()); - DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, speed_flt, e2 - session.engine().frames_per_cycle() )); + speed_flt = (t1 - t0) / double(session.engine().samples_per_cycle()); + DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", t0, t1, e, speed_flt, e2 - session.engine().samples_per_cycle() )); } else { DEBUG_TRACE (DEBUG::LTC, string_compose ("LTC adjusting elapsed (no DLL) from %1 by %2\n", elapsed, (2 * nframes * ltc_speed))); speed_flt = 0; diff --git a/libs/ardour/midi_buffer.cc b/libs/ardour/midi_buffer.cc index b47c3ca152..0b0e61000d 100644 --- a/libs/ardour/midi_buffer.cc +++ b/libs/ardour/midi_buffer.cc @@ -190,55 +190,6 @@ MidiBuffer::push_back(TimeType time, size_t size, const uint8_t* data) return true; } - -/** Push an event into the buffer. - * - * Note that the raw MIDI pointed to by ev will be COPIED and unmodified. - * That is, the caller still owns it, if it needs freeing it's Not My Problem(TM). - * Realtime safe. - * @return false if operation failed (not enough room) - */ -bool -MidiBuffer::push_back(const jack_midi_event_t& ev) -{ - const size_t stamp_size = sizeof(TimeType); - - if (_size + stamp_size + ev.size >= _capacity) { - cerr << "MidiBuffer::push_back failed (buffer is full)" << endl; - return false; - } - - if (!Evoral::midi_event_is_valid(ev.buffer, ev.size)) { - cerr << "WARNING: MidiBuffer ignoring illegal MIDI event" << endl; - return false; - } - -#ifndef NDEBUG - if (DEBUG::MidiIO & PBD::debug_bits) { - DEBUG_STR_DECL(a); - DEBUG_STR_APPEND(a, string_compose ("midibuffer %1 push jack event @ %2 sz %3 ", this, ev.time, ev.size)); - for (size_t i=0; i < ev.size; ++i) { - DEBUG_STR_APPEND(a,hex); - DEBUG_STR_APPEND(a,"0x"); - DEBUG_STR_APPEND(a,(int)ev.buffer[i]); - DEBUG_STR_APPEND(a,' '); - } - DEBUG_STR_APPEND(a,'\n'); - DEBUG_TRACE (DEBUG::MidiIO, DEBUG_STR(a).str()); - } -#endif - - uint8_t* const write_loc = _data + _size; - *((TimeType*)write_loc) = ev.time; - memcpy(write_loc + stamp_size, ev.buffer, ev.size); - - _size += stamp_size + ev.size; - _silent = false; - - return true; -} - - /** Reserve space for a new event in the buffer. * * This call is for copying MIDI directly into the buffer, the data location diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc index 9c11e818ac..ff6147d285 100644 --- a/libs/ardour/midi_diskstream.cc +++ b/libs/ardour/midi_diskstream.cc @@ -1097,7 +1097,7 @@ MidiDiskstream::prep_record_enable () boost::shared_ptr<MidiPort> sp = _source_port.lock (); if (sp && Config->get_monitoring_model() == HardwareMonitoring) { - sp->request_jack_monitors_input (!(_session.config.get_auto_input() && rolling)); + sp->request_input_monitoring (!(_session.config.get_auto_input() && rolling)); } return true; @@ -1250,7 +1250,7 @@ MidiDiskstream::ensure_jack_monitors_input (bool yn) boost::shared_ptr<MidiPort> sp = _source_port.lock (); if (sp) { - sp->ensure_jack_monitors_input (yn); + sp->ensure_input_monitoring (yn); } } diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index 72150f8cfc..9191a57080 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -26,7 +26,9 @@ using namespace ARDOUR; using namespace std; -MidiPort::MidiPort (const std::string& name, Flags flags) +#define port_engine AudioEngine::instance()->port_engine() + +MidiPort::MidiPort (const std::string& name, PortFlags flags) : Port (name, DataType::MIDI, flags) , _has_been_mixed_down (false) , _resolve_required (false) @@ -48,7 +50,7 @@ MidiPort::cycle_start (pframes_t nframes) _buffer->clear (); if (sends_output ()) { - jack_midi_clear_buffer (jack_port_get_buffer (_jack_port, nframes)); + port_engine.midi_clear (port_engine.get_buffer (_port_handle, nframes)); } } @@ -63,31 +65,33 @@ MidiPort::get_midi_buffer (pframes_t nframes) if (_input_active) { - void* jack_buffer = jack_port_get_buffer (_jack_port, nframes); - const pframes_t event_count = jack_midi_get_event_count (jack_buffer); + void* buffer = port_engine.get_buffer (_port_handle, nframes); + const pframes_t event_count = port_engine.get_midi_event_count (buffer); - /* suck all relevant MIDI events from the JACK MIDI port buffer + /* suck all relevant MIDI events from the MIDI port buffer into our MidiBuffer */ for (pframes_t i = 0; i < event_count; ++i) { - jack_midi_event_t ev; + pframes_t timestamp; + size_t size; + uint8_t* buf; - jack_midi_event_get (&ev, jack_buffer, i); + port_engine.midi_event_get (timestamp, size, &buf, buffer, i); - if (ev.buffer[0] == 0xfe) { + if (buf[0] == 0xfe) { /* throw away active sensing */ continue; } /* check that the event is in the acceptable time range */ - if ((ev.time >= (_global_port_buffer_offset + _port_buffer_offset)) && - (ev.time < (_global_port_buffer_offset + _port_buffer_offset + nframes))) { - _buffer->push_back (ev); + if ((timestamp >= (_global_port_buffer_offset + _port_buffer_offset)) && + (timestamp < (_global_port_buffer_offset + _port_buffer_offset + nframes))) { + _buffer->push_back (timestamp, size, buf); } else { - cerr << "Dropping incoming MIDI at time " << ev.time << "; offset=" + cerr << "Dropping incoming MIDI at time " << timestamp << "; offset=" << _global_port_buffer_offset << " limit=" << (_global_port_buffer_offset + _port_buffer_offset + nframes) << "\n"; } @@ -121,7 +125,7 @@ MidiPort::cycle_split () } void -MidiPort::resolve_notes (void* jack_buffer, MidiBuffer::TimeType when) +MidiPort::resolve_notes (void* port_buffer, MidiBuffer::TimeType when) { for (uint8_t channel = 0; channel <= 0xF; channel++) { @@ -132,13 +136,13 @@ MidiPort::resolve_notes (void* jack_buffer, MidiBuffer::TimeType when) * that prioritize sustain over AllNotesOff */ - if (jack_midi_event_write (jack_buffer, when, ev, 3) != 0) { + if (port_engine.midi_event_put (port_buffer, when, ev, 3) != 0) { cerr << "failed to deliver sustain-zero on channel " << channel << " on port " << name() << endl; } ev[1] = MIDI_CTL_ALL_NOTES_OFF; - if (jack_midi_event_write (jack_buffer, 0, ev, 3) != 0) { + if (port_engine.midi_event_put (port_buffer, 0, ev, 3) != 0) { cerr << "failed to deliver ALL NOTES OFF on channel " << channel << " on port " << name() << endl; } } @@ -149,11 +153,11 @@ MidiPort::flush_buffers (pframes_t nframes) { if (sends_output ()) { - void* jack_buffer = jack_port_get_buffer (_jack_port, nframes); - + void* port_buffer = port_engine.get_buffer (_port_handle, nframes); + if (_resolve_required) { /* resolve all notes at the start of the buffer */ - resolve_notes (jack_buffer, 0); + resolve_notes (port_buffer, 0); _resolve_required = false; } @@ -166,7 +170,7 @@ MidiPort::flush_buffers (pframes_t nframes) assert (ev.time() < (nframes + _global_port_buffer_offset + _port_buffer_offset)); if (ev.time() >= _global_port_buffer_offset + _port_buffer_offset) { - if (jack_midi_event_write (jack_buffer, (jack_nframes_t) ev.time(), ev.buffer(), ev.size()) != 0) { + if (port_engine.midi_event_put (port_buffer, (pframes_t) ev.time(), ev.buffer(), ev.size()) != 0) { cerr << "write failed, drop flushed note off on the floor, time " << ev.time() << " > " << _global_port_buffer_offset + _port_buffer_offset << endl; } diff --git a/libs/ardour/midi_ui.cc b/libs/ardour/midi_ui.cc index 78da32e427..0d9ac17601 100644 --- a/libs/ardour/midi_ui.cc +++ b/libs/ardour/midi_ui.cc @@ -107,7 +107,7 @@ MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port) CrossThreadChannel::drain (port->selectable()); DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", port->name())); - framepos_t now = _session.engine().frame_time(); + framepos_t now = _session.engine().sample_time(); port->parse (now); } diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index 8ce0722d8b..0f2761c350 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -579,7 +579,7 @@ MTC_Slave::init_engine_dll (framepos_t pos, framepos_t inc) bool MTC_Slave::speed_and_position (double& speed, framepos_t& pos) { - framepos_t now = session.engine().frame_time_at_cycle_start(); + framepos_t now = session.engine().sample_time_at_cycle_start(); framepos_t sess_pos = session.transport_frame(); // corresponds to now //sess_pos -= session.engine().frames_since_cycle_start(); @@ -593,7 +593,7 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos) if (last.timestamp == 0) { engine_dll_initstate = 0; } else if (engine_dll_initstate != transport_direction && last.speed != 0) { engine_dll_initstate = transport_direction; - init_engine_dll(last.position, session.engine().frames_per_cycle()); + init_engine_dll(last.position, session.engine().samples_per_cycle()); engine_dll_reinitialized = true; } @@ -643,8 +643,8 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos) te0 = te1; te1 += be * e + ee2; ee2 += ce * e; - speed_flt = (te1 - te0) / double(session.engine().frames_per_cycle()); - DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().frames_per_cycle() )); + speed_flt = (te1 - te0) / double(session.engine().samples_per_cycle()); + DEBUG_TRACE (DEBUG::MTC, string_compose ("engine DLL t0:%1 t1:%2 err:%3 spd:%4 ddt:%5\n", te0, te1, e, speed_flt, ee2 - session.engine().samples_per_cycle() )); } } diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index 859f1ff8ab..5a1750a878 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -30,6 +30,7 @@ #include "ardour/audioengine.h" #include "ardour/debug.h" #include "ardour/port.h" +#include "ardour/port_engine.h" #include "i18n.h" @@ -40,13 +41,17 @@ using namespace PBD; PBD::Signal2<void,boost::shared_ptr<Port>, boost::shared_ptr<Port> > Port::PostDisconnect; PBD::Signal0<void> Port::PortDrop; -AudioEngine* Port::_engine = 0; bool Port::_connecting_blocked = false; pframes_t Port::_global_port_buffer_offset = 0; pframes_t Port::_cycle_nframes = 0; +/* a handy define to shorten what would otherwise be a needlessly verbose + * repeated phrase + */ +#define port_engine AudioEngine::instance()->port_engine() + /** @param n Port short name */ -Port::Port (std::string const & n, DataType t, Flags f) +Port::Port (std::string const & n, DataType t, PortFlags f) : _port_buffer_offset (0) , _name (n) , _flags (f) @@ -64,15 +69,15 @@ Port::Port (std::string const & n, DataType t, Flags f) assert (_name.find_first_of (':') == std::string::npos); - if (!_engine->connected()) { + if (!port_engine.connected()) { throw failed_constructor (); } - if ((_jack_port = jack_port_register (_engine->jack (), _name.c_str (), t.to_jack_type (), _flags, 0)) == 0) { + if ((_jack_port = port_engine.register_port (_name, t.to_port_type (), _flags)) == 0) { cerr << "Failed to register JACK port \"" << _name << "\", reason is unknown from here\n"; throw failed_constructor (); } - + PortDrop.connect_same_thread (drop_connection, boost::bind (&Port::drop, this)); } @@ -85,11 +90,9 @@ Port::~Port () void Port::drop () { - if (_jack_port) { - if (_engine->jack ()) { - jack_port_unregister (_engine->jack (), _jack_port); - } - _jack_port = 0; + if (_port_handle) { + port_engine.unregister_port (port_handle); + _port_handle = 0; } } @@ -97,7 +100,7 @@ Port::drop () bool Port::connected () const { - return (jack_port_connected (_jack_port) != 0); + return (port_engine.connected (_port_handle) != 0); } int @@ -191,9 +194,9 @@ Port::disconnect (std::string const & other) int r = 0; if (sends_output ()) { - r = jack_disconnect (_engine->jack (), this_fullname.c_str (), other_fullname.c_str ()); + r = _engine->disconnect (this_fullname, other_fullname); } else { - r = jack_disconnect (_engine->jack (), other_fullname.c_str (), this_fullname.c_str ()); + r = _engine->disconnect (other_fullname, this_fullname); } if (r == 0) { @@ -236,27 +239,22 @@ Port::disconnect (Port* o) } void -Port::set_engine (AudioEngine* e) -{ - _engine = e; -} - -void -Port::request_monitor_input (bool yn) +Port::request_input_monitoring (bool yn) { - jack_port_request_monitor (_jack_port, yn); + port_eengine.request_input_monitoring (_port_handle, yn); } void -Port::ensure_monitor_input (bool yn) +Port::ensure_input_monitoring (bool yn) { - jack_port_ensure_monitor (_jack_port, yn); + port_engine.ensure_input_monitoring (_port_handle, yn); } bool Port::monitoring_input () const { - return jack_port_monitoring_input (_jack_port); + + return port_engine.monitoring_input (_port_handle); } void diff --git a/libs/ardour/wscript b/libs/ardour/wscript index ea08636ea8..20908e5260 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -1,4 +1,4 @@ -#!/usr/bin/env python +1#!/usr/bin/env python from waflib.extras import autowaf as autowaf from waflib import Options import os @@ -432,6 +432,25 @@ def build(bld): elif bld.env['build_target'] == 'x86_64': obj.source += [ 'sse_functions_xmm.cc', 'sse_functions_64bit.s' ] + # the JACK audio backend + + obj = bld.shlib (features = 'c cxx cshlib cxxshlib', source='jack_audiobackend.cc') + obj.cxxflags = [ '-fPIC' ] + obj.name = 'jack_audiobackend' + obj.target = 'jack_audiobackend' + obj.uselib = [ 'JACK' ] + obj.use = [ 'ardour' ] + obj.vnum = '1.0.0' + obj.install_path = os.path.join(bld.env['LIBDIR'], 'ardour3') + obj.includes = [ '.' ] + obj.defines = [ + 'PACKAGE="' + I18N_PACKAGE + '"', + 'DATA_DIR="' + os.path.normpath(bld.env['DATADIR']) + '"', + 'CONFIG_DIR="' + os.path.normpath(bld.env['SYSCONFDIR']) + '"', + 'PROGRAM_NAME="' + bld.env['PROGRAM_NAME'] + '"', + ] + + # i18n if bld.is_defined('ENABLE_NLS'): mo_files = bld.path.ant_glob('po/*.mo') diff --git a/libs/midi++2/jack_midi_port.cc b/libs/midi++2/jack_midi_port.cc index 05df3171fa..372a7891c9 100644 --- a/libs/midi++2/jack_midi_port.cc +++ b/libs/midi++2/jack_midi_port.cc @@ -22,9 +22,6 @@ #include <fcntl.h> #include <errno.h> -#include <jack/jack.h> -#include <jack/midiport.h> - #include "pbd/xml++.h" #include "pbd/error.h" #include "pbd/failed_constructor.h" @@ -45,37 +42,34 @@ template class EventRingBuffer<timestamp_t>; } pthread_t JackMIDIPort::_process_thread; -Signal0<void> JackMIDIPort::JackHalted; +Signal0<void> JackMIDIPort::EngineHalted; Signal0<void> JackMIDIPort::MakeConnections; -JackMIDIPort::JackMIDIPort (string const & name, Flags flags, jack_client_t* jack_client) +JackMIDIPort::JackMIDIPort (string const & name, Flags flags, ARDOUR::PortEngine& pengine) : Port (name, flags) + , _port_engine (pengine) + , _port_handle (0) , _currently_in_cycle (false) , _nframes_this_cycle (0) - , _jack_client (jack_client) - , _jack_port (0) , _last_write_timestamp (0) , output_fifo (512) , input_fifo (1024) , xthread (true) { - assert (jack_client); init (name, flags); } -JackMIDIPort::JackMIDIPort (const XMLNode& node, jack_client_t* jack_client) +JackMIDIPort::JackMIDIPort (const XMLNode& node, ARDOUR::PortEngine& pengine) : Port (node) + , _port_engine (pengine) + , _port_handle (0) , _currently_in_cycle (false) , _nframes_this_cycle (0) - , _jack_client (jack_client) - , _jack_port (0) , _last_write_timestamp (0) , output_fifo (512) , input_fifo (1024) , xthread (true) { - assert (jack_client); - Descriptor desc (node); init (desc.tag, desc.flags); set_state (node); @@ -89,17 +83,15 @@ JackMIDIPort::init (const string& /*name*/, Flags /*flags*/) } MakeConnections.connect_same_thread (connect_connection, boost::bind (&JackMIDIPort::make_connections, this)); - JackHalted.connect_same_thread (halt_connection, boost::bind (&JackMIDIPort::jack_halted, this)); + EngineHalted.connect_same_thread (halt_connection, boost::bind (&JackMIDIPort::engine_halted, this)); } JackMIDIPort::~JackMIDIPort () { - if (_jack_port) { - if (_jack_client) { - jack_port_unregister (_jack_client, _jack_port); - _jack_port = 0; - } + if (_port_handle) { + _port_engine.unregister_port (_port_handle); + _port_handle = 0; } } @@ -143,7 +135,7 @@ JackMIDIPort::parse (framecnt_t timestamp) void JackMIDIPort::cycle_start (pframes_t nframes) { - assert (_jack_port); + assert (_port_handle); _currently_in_cycle = true; _nframes_this_cycle = nframes; @@ -151,21 +143,23 @@ JackMIDIPort::cycle_start (pframes_t nframes) assert(_nframes_this_cycle == nframes); if (sends_output()) { - void *buffer = jack_port_get_buffer (_jack_port, nframes); + void *buffer = _port_engine.get_buffer (_port_handle, nframes); jack_midi_clear_buffer (buffer); flush (buffer); } if (receives_input()) { - void* jack_buffer = jack_port_get_buffer(_jack_port, nframes); - const pframes_t event_count = jack_midi_get_event_count(jack_buffer); + void* buffer = _port_engine.get_buffer (_port_handle, nframes); + const pframes_t event_count = _port_engine.get_midi_event_count (buffer); - jack_midi_event_t ev; - timestamp_t cycle_start_frame = jack_last_frame_time (_jack_client); + pframes_t time; + size_t size; + uint8_t* buf; + timestamp_t cycle_start_frame = _port_engine.last_frame_time (); for (pframes_t i = 0; i < event_count; ++i) { - jack_midi_event_get (&ev, jack_buffer, i); - input_fifo.write (cycle_start_frame + ev.time, (Evoral::EventType) 0, ev.size, ev.buffer); + _port_engine.midi_event_get (time, size, &buf, buffer, i); + input_fifo.write (cycle_start_frame + time, (Evoral::EventType) 0, size, buf); } if (event_count) { @@ -178,7 +172,7 @@ void JackMIDIPort::cycle_end () { if (sends_output()) { - flush (jack_port_get_buffer (_jack_port, _nframes_this_cycle)); + flush (_port_engine.get_buffer (_port_handle, _nframes_this_cycle)); } _currently_in_cycle = false; @@ -186,10 +180,9 @@ JackMIDIPort::cycle_end () } void -JackMIDIPort::jack_halted () +JackMIDIPort::engine_halted () { - _jack_client = 0; - _jack_port = 0; + _port_handle = 0; } void @@ -216,7 +209,7 @@ JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp) { int ret = 0; - if (!_jack_client || !_jack_port) { + if (!_port_handle) { /* poof ! make it just vanish into thin air, since we are no longer connected to JACK. */ @@ -268,18 +261,18 @@ JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp) if (timestamp == 0) { timestamp = _last_write_timestamp; } - - if ((ret = jack_midi_event_write (jack_port_get_buffer (_jack_port, _nframes_this_cycle), - timestamp, msg, msglen)) == 0) { + + if ((ret = _port_engine.midi_event_put (_port_engine.get_buffer (_port_handle, _nframes_this_cycle), + timestamp, msg, msglen)) == 0) { ret = msglen; _last_write_timestamp = timestamp; } else { cerr << "write of " << msglen << " @ " << timestamp << " failed, port holds " - << jack_midi_get_event_count (jack_port_get_buffer (_jack_port, _nframes_this_cycle)) - << " port is " << _jack_port + << _port_engine.get_midi_event_count (_port_engine.get_buffer (_port_handle, _nframes_this_cycle)) + << " port is " << _port_handle << " ntf = " << _nframes_this_cycle - << " buf = " << jack_port_get_buffer (_jack_port, _nframes_this_cycle) + << " buf = " << _port_engine.get_buffer (_port_handle, _nframes_this_cycle) << " ret = " << ret << endl; PBD::stacktrace (cerr, 20); @@ -305,7 +298,7 @@ JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp) } void -JackMIDIPort::flush (void* jack_port_buffer) +JackMIDIPort::flush (void* port_buffer) { RingBuffer< Evoral::Event<double> >::rw_vector vec = { { 0, 0 }, { 0, 0 } }; size_t written; @@ -320,8 +313,7 @@ JackMIDIPort::flush (void* jack_port_buffer) Evoral::Event<double>* evp = vec.buf[0]; for (size_t n = 0; n < vec.len[0]; ++n, ++evp) { - jack_midi_event_write (jack_port_buffer, - (timestamp_t) evp->time(), evp->buffer(), evp->size()); + _port_engine.midi_event_put (port_buffer, (timestamp_t) evp->time(), evp->buffer(), evp->size()); } } @@ -329,8 +321,7 @@ JackMIDIPort::flush (void* jack_port_buffer) Evoral::Event<double>* evp = vec.buf[1]; for (size_t n = 0; n < vec.len[1]; ++n, ++evp) { - jack_midi_event_write (jack_port_buffer, - (timestamp_t) evp->time(), evp->buffer(), evp->size()); + _port_engine.midi_event_put (port_buffer, (timestamp_t) evp->time(), evp->buffer(), evp->size()); } } @@ -364,8 +355,21 @@ JackMIDIPort::read (byte *, size_t) int JackMIDIPort::create_port () { - _jack_port = jack_port_register(_jack_client, _tagname.c_str(), JACK_DEFAULT_MIDI_TYPE, _flags, 0); - return _jack_port == 0 ? -1 : 0; + ARDOUR::PortFlags f = ARDOUR::PortFlags (0); + + /* convert MIDI::Port::Flags to ARDOUR::PortFlags ... sigh */ + + if (_flags & IsInput) { + f = ARDOUR::PortFlags (f | ARDOUR::IsInput); + } + + if (_flags & IsOutput) { + f = ARDOUR::PortFlags (f | ARDOUR::IsOutput); + } + + _port_handle = _port_engine.register_port (_tagname, ARDOUR::DataType::MIDI, f); + + return _port_handle == 0 ? -1 : 0; } XMLNode& @@ -386,18 +390,16 @@ JackMIDIPort::get_state () const write (device_inquiry, sizeof (device_inquiry), 0); #endif - if (_jack_port) { + if (_port_handle) { - const char** jc = jack_port_get_connections (_jack_port); + vector<string> connections; + _port_engine.get_connections (_port_handle, connections); string connection_string; - if (jc) { - for (int i = 0; jc[i]; ++i) { - if (i > 0) { - connection_string += ','; - } - connection_string += jc[i]; + for (vector<string>::iterator i = connections.begin(); i != connections.end(); ++i) { + if (i != connections.begin()) { + connection_string += ','; } - free (jc); + connection_string += *i; } if (!connection_string.empty()) { @@ -435,14 +437,8 @@ JackMIDIPort::make_connections () vector<string> ports; split (_connections, ports, ','); for (vector<string>::iterator x = ports.begin(); x != ports.end(); ++x) { - if (_jack_client) { - if (receives_input()) { - jack_connect (_jack_client, (*x).c_str(), jack_port_name (_jack_port)); - } else { - jack_connect (_jack_client, jack_port_name (_jack_port), (*x).c_str()); - } - /* ignore failures */ - } + _port_engine.connect (_port_handle, *x); + /* ignore failures */ } } @@ -462,9 +458,8 @@ JackMIDIPort::is_process_thread() } void -JackMIDIPort::reestablish (jack_client_t* jack) +JackMIDIPort::reestablish () { - _jack_client = jack; int const r = create_port (); if (r) { diff --git a/libs/midi++2/manager.cc b/libs/midi++2/manager.cc index 822c74e125..3df9681dd3 100644 --- a/libs/midi++2/manager.cc +++ b/libs/midi++2/manager.cc @@ -36,17 +36,17 @@ using namespace PBD; Manager *Manager::theManager = 0; -Manager::Manager (jack_client_t* jack) +Manager::Manager (ARDOUR::PortEngine& eng) : _ports (new PortList) { - _mmc = new MachineControl (this, jack); + _mmc = new MachineControl (this, eng); - _mtc_input_port = add_port (new MIDI::JackMIDIPort ("MTC in", Port::IsInput, jack)); - _mtc_output_port = add_port (new MIDI::JackMIDIPort ("MTC out", Port::IsOutput, jack)); - _midi_input_port = add_port (new MIDI::JackMIDIPort ("MIDI control in", Port::IsInput, jack)); - _midi_output_port = add_port (new MIDI::JackMIDIPort ("MIDI control out", Port::IsOutput, jack)); - _midi_clock_input_port = add_port (new MIDI::JackMIDIPort ("MIDI clock in", Port::IsInput, jack)); - _midi_clock_output_port = add_port (new MIDI::JackMIDIPort ("MIDI clock out", Port::IsOutput, jack)); + _mtc_input_port = add_port (new MIDI::JackMIDIPort ("MTC in", Port::IsInput, eng)); + _mtc_output_port = add_port (new MIDI::JackMIDIPort ("MTC out", Port::IsOutput, eng)); + _midi_input_port = add_port (new MIDI::JackMIDIPort ("MIDI control in", Port::IsInput, eng)); + _midi_output_port = add_port (new MIDI::JackMIDIPort ("MIDI control out", Port::IsOutput, eng)); + _midi_clock_input_port = add_port (new MIDI::JackMIDIPort ("MIDI clock in", Port::IsInput, eng)); + _midi_clock_output_port = add_port (new MIDI::JackMIDIPort ("MIDI clock out", Port::IsOutput, eng)); } Manager::~Manager () @@ -113,14 +113,14 @@ Manager::cycle_end() /** Re-register ports that disappear on JACK shutdown */ void -Manager::reestablish (jack_client_t* jack) +Manager::reestablish () { boost::shared_ptr<PortList> pr = _ports.reader (); for (PortList::const_iterator p = pr->begin(); p != pr->end(); ++p) { JackMIDIPort* pp = dynamic_cast<JackMIDIPort*> (*p); if (pp) { - pp->reestablish (jack); + pp->reestablish (); } } } @@ -157,10 +157,10 @@ Manager::port (string const & n) } void -Manager::create (jack_client_t* jack) +Manager::create (ARDOUR::PortEngine& eng) { assert (theManager == 0); - theManager = new Manager (jack); + theManager = new Manager (eng); } void diff --git a/libs/midi++2/midi++/jack_midi_port.h b/libs/midi++2/midi++/jack_midi_port.h index a8859387a4..492756067c 100644 --- a/libs/midi++2/midi++/jack_midi_port.h +++ b/libs/midi++2/midi++/jack_midi_port.h @@ -22,8 +22,6 @@ #include <string> #include <iostream> -#include <jack/types.h> - #include "pbd/xml++.h" #include "pbd/crossthread.h" #include "pbd/signals.h" @@ -36,6 +34,8 @@ #include "midi++/parser.h" #include "midi++/port.h" +#include "ardour/port_engine.h" + namespace MIDI { class Channel; @@ -43,8 +43,8 @@ class PortRequest; class JackMIDIPort : public Port { public: - JackMIDIPort (std::string const &, Port::Flags, jack_client_t *); - JackMIDIPort (const XMLNode&, jack_client_t *); + JackMIDIPort (std::string const &, Port::Flags, ARDOUR::PortEngine&); + JackMIDIPort (const XMLNode&, ARDOUR::PortEngine&); ~JackMIDIPort (); XMLNode& get_state () const; @@ -61,7 +61,7 @@ class JackMIDIPort : public Port { pframes_t nframes_this_cycle() const { return _nframes_this_cycle; } - void reestablish (jack_client_t *); + void reestablish (); void reconnect (); static void set_process_thread (pthread_t); @@ -69,13 +69,14 @@ class JackMIDIPort : public Port { static bool is_process_thread(); static PBD::Signal0<void> MakeConnections; - static PBD::Signal0<void> JackHalted; + static PBD::Signal0<void> EngineHalted; private: + ARDOUR::PortEngine& _port_engine; + ARDOUR::PortEngine::PortHandle _port_handle; + bool _currently_in_cycle; pframes_t _nframes_this_cycle; - jack_client_t* _jack_client; - jack_port_t* _jack_port; timestamp_t _last_write_timestamp; RingBuffer< Evoral::Event<double> > output_fifo; Evoral::EventRingBuffer<timestamp_t> input_fifo; @@ -89,8 +90,8 @@ private: std::string _connections; PBD::ScopedConnection connect_connection; PBD::ScopedConnection halt_connection; - void flush (void* jack_port_buffer); - void jack_halted (); + void flush (void* port_buffer); + void engine_halted (); void make_connections (); void init (std::string const &, Flags); diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h index c37ba392b4..7f4df5c6c8 100644 --- a/libs/midi++2/midi++/manager.h +++ b/libs/midi++2/midi++/manager.h @@ -29,6 +29,10 @@ #include "midi++/types.h" #include "midi++/port.h" +namespace ARDOUR { + class PortEngine; +} + namespace MIDI { class MachineControl; @@ -69,14 +73,14 @@ class Manager { boost::shared_ptr<const PortList> get_midi_ports() const { return _ports.reader (); } - static void create (jack_client_t* jack); + static void create (ARDOUR::PortEngine&); static Manager *instance () { return theManager; } static void destroy (); - void reestablish (jack_client_t *); + void reestablish (); void reconnect (); PBD::Signal0<void> PortsChanged; @@ -84,7 +88,7 @@ class Manager { private: /* This is a SINGLETON pattern */ - Manager (jack_client_t *); + Manager (ARDOUR::PortEngine&); static Manager *theManager; MIDI::MachineControl* _mmc; diff --git a/libs/midi++2/midi++/mmc.h b/libs/midi++2/midi++/mmc.h index 18204e3fa8..0f362678ce 100644 --- a/libs/midi++2/midi++/mmc.h +++ b/libs/midi++2/midi++/mmc.h @@ -22,11 +22,17 @@ #include <jack/types.h> #include "timecode/time.h" + #include "pbd/signals.h" #include "pbd/ringbuffer.h" + #include "midi++/types.h" #include "midi++/parser.h" +namespace ARDOUR { + class PortEngine; +} + namespace MIDI { class Port; @@ -89,7 +95,7 @@ class MachineControl cmdResume = 0x7F }; - MachineControl (Manager *, jack_client_t *); + MachineControl (Manager *, ARDOUR::PortEngine&); Port* input_port() { return _input_port; } Port* output_port() { return _output_port; } diff --git a/libs/midi++2/mmc.cc b/libs/midi++2/mmc.cc index 06eadb5b34..0a71463721 100644 --- a/libs/midi++2/mmc.cc +++ b/libs/midi++2/mmc.cc @@ -22,7 +22,9 @@ #include <map> #include "timecode/time.h" + #include "pbd/error.h" + #include "midi++/mmc.h" #include "midi++/port.h" #include "midi++/jack_midi_port.h" @@ -196,15 +198,15 @@ static void build_mmc_cmd_map () } -MachineControl::MachineControl (Manager* m, jack_client_t* jack) +MachineControl::MachineControl (Manager* m, ARDOUR::PortEngine& pengine) { build_mmc_cmd_map (); _receive_device_id = 0x7f; _send_device_id = 0x7f; - _input_port = m->add_port (new JackMIDIPort ("MMC in", Port::IsInput, jack)); - _output_port = m->add_port (new JackMIDIPort ("MMC out", Port::IsOutput, jack)); + _input_port = m->add_port (new JackMIDIPort ("MMC in", Port::IsInput, pengine)); + _output_port = m->add_port (new JackMIDIPort ("MMC out", Port::IsOutput, pengine)); _input_port->parser()->mmc.connect_same_thread (port_connections, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3)); _input_port->parser()->start.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_start, this)); diff --git a/libs/midi++2/wscript b/libs/midi++2/wscript index ea8988110d..8a4f2f6c69 100644 --- a/libs/midi++2/wscript +++ b/libs/midi++2/wscript @@ -26,6 +26,7 @@ out = 'build' path_prefix = 'libs/midi++2/' + libmidi_sources = [ 'midi.cc', 'channel.cc', @@ -68,7 +69,7 @@ def build(bld): obj.cxxflags = [ '-fPIC', '-DWITH_JACK_MIDI' ] # everybody loves JACK obj.export_includes = ['.'] - obj.includes = ['.', '../surfaces/control_protocol'] + obj.includes = ['.', '../surfaces/control_protocol', '../ardour' ] obj.name = 'libmidipp' obj.target = 'midipp' obj.uselib = 'GLIBMM SIGCPP XML JACK OSX' diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc index cfa6524f70..ffda2435d0 100644 --- a/libs/surfaces/mackie/mackie_control_protocol.cc +++ b/libs/surfaces/mackie/mackie_control_protocol.cc @@ -1236,7 +1236,7 @@ MackieControlProtocol::midi_input_handler (IOCondition ioc, MIDI::Port* port) } DEBUG_TRACE (DEBUG::MackieControl, string_compose ("data available on %1\n", port->name())); - framepos_t now = session->engine().frame_time(); + framepos_t now = session->engine().sample_time(); port->parse (now); } diff --git a/libs/surfaces/mackie/surface_port.cc b/libs/surfaces/mackie/surface_port.cc index 9f52f0dccd..44db30ab1b 100644 --- a/libs/surfaces/mackie/surface_port.cc +++ b/libs/surfaces/mackie/surface_port.cc @@ -59,10 +59,10 @@ SurfacePort::SurfacePort (Surface& s) _input_port = new MIDI::IPMIDIPort (_surface->mcp().ipmidi_base() +_surface->number()); _output_port = _input_port; } else { - jack_client_t* jack = MackieControlProtocol::instance()->get_session().engine().jack(); + ARDOUR::PortEngine& port_engine (ARDOUR::AudioEngine::instance()->port_engine()); - _input_port = new MIDI::JackMIDIPort (string_compose (_("%1 in"), _surface->name()), MIDI::Port::IsInput, jack); - _output_port =new MIDI::JackMIDIPort (string_compose (_("%1 out"), _surface->name()), MIDI::Port::IsOutput, jack); + _input_port = new MIDI::JackMIDIPort (string_compose (_("%1 in"), _surface->name()), MIDI::Port::IsInput, port_engine); + _output_port =new MIDI::JackMIDIPort (string_compose (_("%1 out"), _surface->name()), MIDI::Port::IsOutput, port_engine); /* MackieControl has its own thread for handling input from the input * port, and we don't want anything handling output from the output |