From 20b1a7d9d8800f8fdca8379cba01cc39757c34fc Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 25 Jul 2013 12:36:54 -0400 Subject: most of libardour now actually compiles --- libs/ardour/session_export.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'libs/ardour/session_export.cc') diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index 0db4fc33bb..02bf48a0d6 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.connected()) { + if (!_engine.port_engine().connected()) { return -1; } -- cgit v1.2.3 From 682ebad62bdc85df151ad0b81dc27cc9f3e71cec Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 1 Aug 2013 14:43:12 -0400 Subject: 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 | 309 +++++++++++++++++++++++++++------ 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, 536 insertions(+), 212 deletions(-) (limited to 'libs/ardour/session_export.cc') 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(); + + 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); +} - 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); +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; + + const char** ports = jack_port_get_connections ((jack_port_t*) port); + + if (ports) { + ret = true; + } + + jack_free (ports); + + return ret; } -int -JACKPortEngine::graph_order_callback () +bool +JACKPortEngine::connected_to (PortHandle port, const std::string& other) { - if (_jack_connection->connected()) { - _manager->graph_order_callback (); + 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 0; + 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); -- cgit v1.2.3 From 1ab61b8564f9934c533d1c1a229888bc7e2fd557 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 7 Aug 2013 22:22:11 -0400 Subject: major redesign of MIDI port heirarchy and management (part 2) --- gtk2_ardour/ardour_ui.cc | 42 +++-- gtk2_ardour/editor.cc | 3 +- gtk2_ardour/editor_drag.cc | 5 +- gtk2_ardour/gain_meter.cc | 1 - gtk2_ardour/generic_pluginui.cc | 2 - gtk2_ardour/level_meter.cc | 1 - gtk2_ardour/midi_tracer.cc | 45 +++++- gtk2_ardour/panner_ui.cc | 1 - gtk2_ardour/plugin_ui.cc | 2 - gtk2_ardour/port_group.cc | 28 ++-- gtk2_ardour/rc_option_editor.cc | 2 - libs/ardour/ardour/audio_port.h | 4 +- libs/ardour/ardour/audioengine.h | 11 +- libs/ardour/ardour/debug.h | 1 + libs/ardour/ardour/jack_audiobackend.h | 2 + libs/ardour/ardour/midi_ui.h | 6 +- libs/ardour/ardour/midiport_manager.h | 10 +- libs/ardour/ardour/port_manager.h | 35 +++- libs/ardour/ardour/session.h | 2 +- libs/ardour/ardour/slave.h | 30 ++-- libs/ardour/ardour/ticker.h | 53 +++--- libs/ardour/audioengine.cc | 138 ++++++---------- libs/ardour/debug.cc | 1 + libs/ardour/globals.cc | 5 +- libs/ardour/jack_audiobackend.cc | 6 +- libs/ardour/jack_connection.cc | 5 +- libs/ardour/ladspa_plugin.cc | 2 - libs/ardour/midi_clock_slave.cc | 44 +++-- libs/ardour/midi_ui.cc | 40 ++--- libs/ardour/midiport_manager.cc | 40 ++++- libs/ardour/mtc_slave.cc | 49 ++++-- libs/ardour/port.cc | 1 + libs/ardour/port_manager.cc | 128 +++++++++++++-- libs/ardour/rc_configuration.cc | 16 +- libs/ardour/session.cc | 20 ++- libs/ardour/session_export.cc | 7 +- libs/ardour/session_midi.cc | 20 +-- libs/ardour/session_process.cc | 6 +- libs/ardour/session_state.cc | 53 +++--- libs/ardour/session_transport.cc | 19 +-- libs/ardour/ticker.cc | 180 ++++++++++----------- libs/ardour/wscript | 2 + libs/midi++2/midi++/mmc.h | 5 +- libs/midi++2/midi++/parser.h | 4 +- libs/midi++2/midi++/port.h | 7 - libs/midi++2/mmc.cc | 15 +- libs/midi++2/parser.cc | 3 +- libs/midi++2/port.cc | 2 +- libs/midi++2/wscript | 2 - .../generic_midi/generic_midi_control_protocol.cc | 19 +-- .../generic_midi/generic_midi_control_protocol.h | 18 ++- libs/surfaces/generic_midi/midiaction.cc | 2 +- libs/surfaces/generic_midi/midiaction.h | 4 +- libs/surfaces/generic_midi/midicontrollable.cc | 38 ++--- libs/surfaces/generic_midi/midicontrollable.h | 15 +- libs/surfaces/generic_midi/midifunction.cc | 2 +- libs/surfaces/generic_midi/midifunction.h | 3 +- libs/surfaces/generic_midi/midiinvokable.cc | 22 +-- libs/surfaces/generic_midi/midiinvokable.h | 7 +- libs/surfaces/mackie/surface.cc | 1 - libs/surfaces/mackie/surface_port.cc | 47 ++---- libs/surfaces/mackie/surface_port.h | 23 ++- 62 files changed, 743 insertions(+), 564 deletions(-) (limited to 'libs/ardour/session_export.cc') diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index a3ea2b1612..69e2a339dd 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -58,8 +58,6 @@ #include "gtkmm2ext/popup.h" #include "gtkmm2ext/window_title.h" -#include "midi++/manager.h" - #include "ardour/ardour.h" #include "ardour/audio_backend.h" #include "ardour/audioengine.h" @@ -1050,14 +1048,20 @@ ARDOUR_UI::update_sample_rate (framecnt_t) framecnt_t rate = engine->sample_rate(); - if (fmod (rate, 1000.0) != 0.0) { - snprintf (buf, sizeof (buf), _("JACK: %.1f kHz / %4.1f ms"), - (float) rate / 1000.0f, - (engine->usecs_per_cycle() / 1000.0f)); + if (rate == 0) { + /* no sample rate available */ + snprintf (buf, sizeof (buf), _("Audio: disconnected")); } else { - snprintf (buf, sizeof (buf), _("JACK: %" PRId64 " kHz / %4.1f ms"), - rate/1000, - (engine->usecs_per_cycle() * 1000.0f)); + + if (fmod (rate, 1000.0) != 0.0) { + snprintf (buf, sizeof (buf), _("Audio: %.1f kHz / %4.1f ms"), + (float) rate / 1000.0f, + (engine->usecs_per_cycle() / 1000.0f)); + } else { + snprintf (buf, sizeof (buf), _("Audio: %" PRId64 " kHz / %4.1f ms"), + rate/1000, + (engine->usecs_per_cycle() * 1000.0f)); + } } } @@ -1181,6 +1185,11 @@ ARDOUR_UI::update_disk_space() char buf[64]; framecnt_t fr = _session->frame_rate(); + if (fr == 0) { + /* skip update - no SR available */ + return; + } + if (!opt_frames) { /* Available space is unknown */ snprintf (buf, sizeof (buf), "%s", _("Disk: Unknown")); @@ -1662,10 +1671,17 @@ ARDOUR_UI::transport_goto_wallclock () time (&now); localtime_r (&now, &tmnow); + + int frame_rate = _session->frame_rate(); + + if (frame_rate == 0) { + /* no frame rate available */ + return; + } - frames = tmnow.tm_hour * (60 * 60 * _session->frame_rate()); - frames += tmnow.tm_min * (60 * _session->frame_rate()); - frames += tmnow.tm_sec * _session->frame_rate(); + frames = tmnow.tm_hour * (60 * 60 * frame_rate); + frames += tmnow.tm_min * (60 * frame_rate); + frames += tmnow.tm_sec * frame_rate; _session->request_locate (frames, _session->transport_rolling ()); @@ -3802,7 +3818,7 @@ void ARDOUR_UI::disconnect_from_jack () { if (engine) { - if (engine->pause ()) { + if (engine->stop ()) { MessageDialog msg (*editor, _("Could not disconnect from JACK")); msg.run (); } diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 300e317a38..a0418892e7 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -1258,7 +1258,8 @@ Editor::set_session (Session *t) /* These signals can all be emitted by a non-GUI thread. Therefore the handlers for them must not attempt to directly interact with the GUI, - but use Gtkmm2ext::UI::instance()->call_slot(); + but use PBD::Signal::connect() which accepts an event loop + ("context") where the handler will be asked to run. */ _session->StepEditStatusChange.connect (_session_connections, invalidator (*this), boost::bind (&Editor::step_edit_status_change, this, _1), gui_context()); diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index b083e851c5..3389164f50 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -2372,8 +2372,9 @@ CursorDrag::fake_locate (framepos_t t) if (s->timecode_transmission_suspended ()) { framepos_t const f = _editor->playhead_cursor->current_frame; s->send_mmc_locate (f); - s->send_full_time_code (f); - s->send_song_position_pointer (f); + // XXX need to queue full time code and SPP messages somehow + // s->send_full_time_code (f); + // s->send_song_position_pointer (f); } show_verbose_cursor_time (t); diff --git a/gtk2_ardour/gain_meter.cc b/gtk2_ardour/gain_meter.cc index 10512b24d0..b2beb5b9a3 100644 --- a/gtk2_ardour/gain_meter.cc +++ b/gtk2_ardour/gain_meter.cc @@ -32,7 +32,6 @@ #include #include #include -#include "midi++/manager.h" #include "pbd/fastlog.h" #include "pbd/stacktrace.h" diff --git a/gtk2_ardour/generic_pluginui.cc b/gtk2_ardour/generic_pluginui.cc index 971dfc0e9b..4405d05c1c 100644 --- a/gtk2_ardour/generic_pluginui.cc +++ b/gtk2_ardour/generic_pluginui.cc @@ -37,8 +37,6 @@ #include #include -#include "midi++/manager.h" - #include "ardour/plugin.h" #include "ardour/plugin_insert.h" #include "ardour/session.h" diff --git a/gtk2_ardour/level_meter.cc b/gtk2_ardour/level_meter.cc index 6f48864992..bf9823518b 100644 --- a/gtk2_ardour/level_meter.cc +++ b/gtk2_ardour/level_meter.cc @@ -23,7 +23,6 @@ #include #include -#include "midi++/manager.h" #include "pbd/fastlog.h" #include "ardour_ui.h" diff --git a/gtk2_ardour/midi_tracer.cc b/gtk2_ardour/midi_tracer.cc index 073fd9cc15..fee339d126 100644 --- a/gtk2_ardour/midi_tracer.cc +++ b/gtk2_ardour/midi_tracer.cc @@ -24,7 +24,10 @@ #include #include "midi++/parser.h" -#include "midi++/manager.h" + +#include "ardour/async_midi_port.h" +#include "ardour/midi_port.h" +#include "ardour/audioengine.h" #include "midi_tracer.h" #include "gui_thread.h" @@ -53,7 +56,8 @@ MidiTracer::MidiTracer () , collect_button (_("Enabled")) , delta_time_button (_("Delta times")) { - Manager::instance()->PortsChanged.connect (_manager_connection, invalidator (*this), boost::bind (&MidiTracer::ports_changed, this), gui_context()); + ARDOUR::AudioEngine::instance()->PortRegisteredOrUnregistered.connect + (_manager_connection, invalidator (*this), boost::bind (&MidiTracer::ports_changed, this), gui_context()); _last_receipt.tv_sec = 0; _last_receipt.tv_usec = 0; @@ -126,25 +130,50 @@ MidiTracer::ports_changed () { string const c = _port_combo.get_active_text (); _port_combo.clear (); + + ARDOUR::PortManager::PortList pl; + ARDOUR::AudioEngine::instance()->get_ports (ARDOUR::DataType::MIDI, pl); + + if (pl.empty()) { + _port_combo.set_active_text (""); + return; + } - boost::shared_ptr p = Manager::instance()->get_midi_ports (); - for (Manager::PortList::const_iterator i = p->begin(); i != p->end(); ++i) { + for (ARDOUR::PortManager::PortList::const_iterator i = pl.begin(); i != pl.end(); ++i) { _port_combo.append_text ((*i)->name()); } - _port_combo.set_active_text (c); + if (c.empty()) { + _port_combo.set_active_text (pl.front()->name()); + } else { + _port_combo.set_active_text (c); + } } void MidiTracer::port_changed () { + using namespace ARDOUR; + disconnect (); - Port* p = Manager::instance()->port (_port_combo.get_active_text()); + boost::shared_ptr p = AudioEngine::instance()->get_port_by_name (_port_combo.get_active_text()); + + if (!p) { + std::cerr << "port not found\n"; + return; + } + + boost::shared_ptr async = boost::dynamic_pointer_cast (p); - if (p) { - p->parser()->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3)); + if (!async) { + /* pure ARDOUR::MidiPort ... cannot currently attach to it because it + * has no Parser. + */ + return; } + + async->parser()->any.connect_same_thread (_parser_connection, boost::bind (&MidiTracer::tracer, this, _1, _2, _3)); } void diff --git a/gtk2_ardour/panner_ui.cc b/gtk2_ardour/panner_ui.cc index 181664bb4e..c82a44f399 100644 --- a/gtk2_ardour/panner_ui.cc +++ b/gtk2_ardour/panner_ui.cc @@ -21,7 +21,6 @@ #include #include -#include "midi++/manager.h" #include "pbd/fastlog.h" #include "ardour/pannable.h" diff --git a/gtk2_ardour/plugin_ui.cc b/gtk2_ardour/plugin_ui.cc index d9741f5e39..713b98cdaf 100644 --- a/gtk2_ardour/plugin_ui.cc +++ b/gtk2_ardour/plugin_ui.cc @@ -40,8 +40,6 @@ #include #include -#include "midi++/manager.h" - #include "ardour/session.h" #include "ardour/plugin.h" #include "ardour/plugin_insert.h" diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc index 5b4f151da8..f8c8e2bde2 100644 --- a/gtk2_ardour/port_group.cc +++ b/gtk2_ardour/port_group.cc @@ -21,7 +21,6 @@ #include #include -#include "midi++/manager.h" #include "midi++/mmc.h" #include "ardour/audioengine.h" @@ -29,9 +28,13 @@ #include "ardour/bundle.h" #include "ardour/control_protocol_manager.h" #include "ardour/io_processor.h" +#include "ardour/midi_port.h" +#include "ardour/midiport_manager.h" #include "ardour/session.h" #include "ardour/user_bundle.h" #include "ardour/port.h" +#include "ardour/syncport_manager.h" + #include "control_protocol/control_protocol.h" #include "gui_thread.h" @@ -452,37 +455,36 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp /* Ardour's sync ports */ - MIDI::Manager* midi_manager = MIDI::Manager::instance (); - if (midi_manager && (type == DataType::MIDI || type == DataType::NIL)) { + if ((type == DataType::MIDI || type == DataType::NIL)) { boost::shared_ptr sync (new Bundle (_("Sync"), inputs)); - MIDI::MachineControl* mmc = midi_manager->mmc (); - AudioEngine& ae = session->engine (); + AudioEngine* ae = AudioEngine::instance(); + MIDI::MachineControl& mmc (ae->mmc()); if (inputs) { sync->add_channel ( - _("MTC in"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->mtc_input_port()->name()) + _("MTC in"), DataType::MIDI, ae->make_port_name_non_relative (ae->mtc_input_port()->name()) ); sync->add_channel ( - _("MIDI control in"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_input_port()->name()) + _("MIDI control in"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_input_port()->name()) ); sync->add_channel ( - _("MIDI clock in"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_clock_input_port()->name()) + _("MIDI clock in"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_clock_input_port()->name()) ); sync->add_channel ( - _("MMC in"), DataType::MIDI, ae.make_port_name_non_relative (mmc->input_port()->name()) + _("MMC in"), DataType::MIDI, ae->make_port_name_non_relative (mmc.input_port()->name()) ); } else { sync->add_channel ( - _("MTC out"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->mtc_output_port()->name()) + _("MTC out"), DataType::MIDI, ae->make_port_name_non_relative (ae->mtc_output_port()->name()) ); sync->add_channel ( - _("MIDI control out"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_output_port()->name()) + _("MIDI control out"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_output_port()->name()) ); sync->add_channel ( - _("MIDI clock out"), DataType::MIDI, ae.make_port_name_non_relative (midi_manager->midi_clock_output_port()->name()) + _("MIDI clock out"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_clock_output_port()->name()) ); sync->add_channel ( - _("MMC out"), DataType::MIDI, ae.make_port_name_non_relative (mmc->output_port()->name()) + _("MMC out"), DataType::MIDI, ae->make_port_name_non_relative (mmc.output_port()->name()) ); } diff --git a/gtk2_ardour/rc_option_editor.cc b/gtk2_ardour/rc_option_editor.cc index 54b96bbb8d..ed9ffda4ef 100644 --- a/gtk2_ardour/rc_option_editor.cc +++ b/gtk2_ardour/rc_option_editor.cc @@ -31,8 +31,6 @@ #include "pbd/fpu.h" #include "pbd/cpus.h" -#include "midi++/manager.h" - #include "ardour/audioengine.h" #include "ardour/dB.h" #include "ardour/rc_configuration.h" diff --git a/libs/ardour/ardour/audio_port.h b/libs/ardour/ardour/audio_port.h index f5affb0580..f87b134e9e 100644 --- a/libs/ardour/ardour/audio_port.h +++ b/libs/ardour/ardour/audio_port.h @@ -49,9 +49,7 @@ class AudioPort : public Port friend class PortManager; AudioPort (std::string const &, PortFlags); - protected: - friend class AudioEngine; - /* special access for engine only (hah, C++) */ + /* special access for PortManager only (hah, C++) */ Sample* engine_get_whole_audio_buffer (); private: diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 6fb13b7ae0..509d330f12 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -36,13 +36,9 @@ #include "pbd/signals.h" #include "pbd/stacktrace.h" -#include -#include -#include -#include +#include "midi++/mmc.h" #include "ardour/ardour.h" - #include "ardour/data_type.h" #include "ardour/session_handle.h" #include "ardour/types.h" @@ -192,6 +188,8 @@ public: /* sets up the process callback thread */ static void thread_init_callback (void *); + MIDI::MachineControl& mmc() { return _mmc; } + private: AudioEngine (); @@ -206,16 +204,17 @@ public: gain_t session_removal_gain; gain_t session_removal_gain_step; bool _running; + bool _freewheeling; /// number of frames between each check for changes in monitor input framecnt_t monitor_check_interval; /// time of the last monitor check in frames framecnt_t last_monitor_check; /// the number of frames processed since start() was called framecnt_t _processed_frames; - bool _freewheeling; bool _pre_freewheel_mmc_enabled; Glib::Threads::Thread* m_meter_thread; ProcessThread* _main_thread; + MIDI::MachineControl _mmc; void meter_thread (); void start_metering_thread (); diff --git a/libs/ardour/ardour/debug.h b/libs/ardour/ardour/debug.h index 202d0cc424..5811f7a484 100644 --- a/libs/ardour/ardour/debug.h +++ b/libs/ardour/ardour/debug.h @@ -63,6 +63,7 @@ namespace PBD { extern uint64_t OrderKeys; extern uint64_t Automation; extern uint64_t WiimoteControl; + extern uint64_t Ports; } } diff --git a/libs/ardour/ardour/jack_audiobackend.h b/libs/ardour/ardour/jack_audiobackend.h index 9fa3d0c1cc..ada7ce8e33 100644 --- a/libs/ardour/ardour/jack_audiobackend.h +++ b/libs/ardour/ardour/jack_audiobackend.h @@ -178,6 +178,8 @@ class JACKAudioBackend : public AudioBackend { typedef std::map DriverDeviceMap; mutable DriverDeviceMap all_devices; + + PBD::ScopedConnection disconnect_connection; }; } // namespace diff --git a/libs/ardour/ardour/midi_ui.h b/libs/ardour/ardour/midi_ui.h index 34e97494be..c15a530057 100644 --- a/libs/ardour/ardour/midi_ui.h +++ b/libs/ardour/ardour/midi_ui.h @@ -26,13 +26,11 @@ #include "pbd/signals.h" #include "pbd/stacktrace.h" -namespace MIDI { - class Port; -} namespace ARDOUR { class Session; +class AsyncMIDIPort; /* this is mostly a placeholder because I suspect that at some point we will want to add more members to accomodate @@ -67,7 +65,7 @@ class MidiControlUI : public AbstractUI ARDOUR::Session& _session; PBD::ScopedConnection rebind_connection; - bool midi_input_handler (Glib::IOCondition, MIDI::Port*); + bool midi_input_handler (Glib::IOCondition, AsyncMIDIPort*); void reset_ports (); void clear_ports (); diff --git a/libs/ardour/ardour/midiport_manager.h b/libs/ardour/ardour/midiport_manager.h index 9c45e60341..df33038f2b 100644 --- a/libs/ardour/ardour/midiport_manager.h +++ b/libs/ardour/ardour/midiport_manager.h @@ -56,8 +56,10 @@ class MidiPortManager { * callback. */ - MIDI::Port* midi_input_port () { return _midi_input_port; } - MIDI::Port* midi_output_port () { return _midi_output_port; } + MIDI::Port* midi_input_port () const { return _midi_input_port; } + MIDI::Port* midi_output_port () const { return _midi_output_port; } + MIDI::Port* mmc_input_port () const { return _mmc_input_port; } + MIDI::Port* mmc_output_port () const { return _mmc_output_port; } /* Ports used for synchronization. These have their I/O handled inside the * process callback. @@ -76,8 +78,12 @@ class MidiPortManager { /* asynchronously handled ports: MIDI::Port */ MIDI::Port* _midi_input_port; MIDI::Port* _midi_output_port; + MIDI::Port* _mmc_input_port; + MIDI::Port* _mmc_output_port; boost::shared_ptr _midi_in; boost::shared_ptr _midi_out; + boost::shared_ptr _mmc_in; + boost::shared_ptr _mmc_out; /* synchronously handled ports: ARDOUR::MidiPort */ boost::shared_ptr _mtc_input_port; diff --git a/libs/ardour/ardour/port_manager.h b/libs/ardour/ardour/port_manager.h index 06e4939101..895294810e 100644 --- a/libs/ardour/ardour/port_manager.h +++ b/libs/ardour/ardour/port_manager.h @@ -32,15 +32,17 @@ #include "pbd/rcu.h" #include "ardour/chan_count.h" +#include "ardour/midiport_manager.h" #include "ardour/port.h" #include "ardour/port_engine.h" namespace ARDOUR { -class PortManager +class PortManager : public MidiPortManager { public: typedef std::map > Ports; + typedef std::list > PortList; PortManager (); virtual ~PortManager() {} @@ -53,8 +55,8 @@ class PortManager /* Port registration */ - boost::shared_ptr register_input_port (DataType, const std::string& portname); - boost::shared_ptr register_output_port (DataType, const std::string& portname); + boost::shared_ptr register_input_port (DataType, const std::string& portname, bool async = false); + boost::shared_ptr register_output_port (DataType, const std::string& portname, bool async = false); int unregister_port (boost::shared_ptr); /* Port connectivity */ @@ -87,7 +89,8 @@ class PortManager ChanCount n_physical_inputs () const; int get_ports (const std::string& port_name_pattern, DataType type, PortFlags flags, std::vector&); - + int get_ports (DataType, PortList&); + void remove_all_ports (); /* per-Port monitoring */ @@ -135,9 +138,31 @@ class PortManager SerializedRCUManager ports; bool _port_remove_in_progress; - boost::shared_ptr register_port (DataType type, const std::string& portname, bool input); + boost::shared_ptr register_port (DataType type, const std::string& portname, bool input, bool async = false); void port_registration_failure (const std::string& portname); + + /** List of ports to be used between ::cycle_start() and ::cycle_end() + */ + boost::shared_ptr _cycle_ports; + + void fade_out (gain_t, gain_t, pframes_t); + void silence (pframes_t nframes); + void check_monitoring (); + /** Signal the start of an audio cycle. + * This MUST be called before any reading/writing for this cycle. + * Realtime safe. + */ + void cycle_start (pframes_t nframes); + + /** Signal the end of an audio cycle. + * This signifies that the cycle began with @ref cycle_start has ended. + * This MUST be called at the end of each cycle. + * Realtime safe. + */ + void cycle_end (pframes_t nframes); }; + + } // namespace diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index a12f816c1e..a47c13046d 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -813,7 +813,7 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi boost::shared_ptr playlists; void send_mmc_locate (framepos_t); - int send_full_time_code (framepos_t); + int send_full_time_code (framepos_t, pframes_t nframes); void send_song_position_pointer (framepos_t); bool step_editing() const { return (_step_editors > 0); } diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index 4408da2d25..adf425ea43 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -40,15 +40,12 @@ #define PLUSMINUS(A) ( ((A)<0) ? "-" : (((A)>0) ? "+" : "\u00B1") ) #define LEADINGZERO(A) ( (A)<10 ? " " : (A)<100 ? " " : (A)<1000 ? " " : "" ) -namespace MIDI { - class Port; -} - namespace ARDOUR { class TempoMap; class Session; class AudioEngine; +class MidiPort; /** * @class Slave @@ -67,6 +64,15 @@ class Slave { Slave() { } virtual ~Slave() {} + /** The slave should read any incoming information in this method + * and use it adjust its current idea of reality. If no such + * processing is required, it does need to be implemented. + * + * @param nframes specifies the number of frames-worth of data that + * can be read from any ports used by the slave. + */ + virtual int process (pframes_t) { return 0; } + /** * This is the most important function to implement: * Each process cycle, Session::follow_slave will call this method. @@ -253,10 +259,11 @@ class TimecodeSlave : public Slave { class MTC_Slave : public TimecodeSlave { public: - MTC_Slave (Session&, MIDI::Port&); + MTC_Slave (Session&, MidiPort&); ~MTC_Slave (); - void rebind (MIDI::Port&); + void rebind (MidiPort&); + int process (pframes_t); bool speed_and_position (double&, framepos_t&); bool locked() const; @@ -274,7 +281,8 @@ class MTC_Slave : public TimecodeSlave { private: Session& session; - MIDI::Port* port; + MidiPort* port; + MIDI::Parser parser; PBD::ScopedConnectionList port_connections; PBD::ScopedConnection config_connection; bool can_notify_on_unknown_rate; @@ -405,13 +413,14 @@ public: class MIDIClock_Slave : public Slave { public: - MIDIClock_Slave (Session&, MIDI::Port&, int ppqn = 24); + MIDIClock_Slave (Session&, MidiPort&, int ppqn = 24); /// Constructor for unit tests MIDIClock_Slave (ISlaveSessionProxy* session_proxy = 0, int ppqn = 24); ~MIDIClock_Slave (); - void rebind (MIDI::Port&); + void rebind (MidiPort&); + int process (pframes_t); bool speed_and_position (double&, framepos_t&); bool locked() const; @@ -427,7 +436,8 @@ class MIDIClock_Slave : public Slave { protected: ISlaveSessionProxy* session; - MIDI::Port* port; + MidiPort* port; + MIDI::Parser parser; PBD::ScopedConnectionList port_connections; /// pulses per quarter note for one MIDI clock frame (default 24) diff --git a/libs/ardour/ardour/ticker.h b/libs/ardour/ardour/ticker.h index b6e5376c12..7f0d1987fc 100644 --- a/libs/ardour/ardour/ticker.h +++ b/libs/ardour/ardour/ticker.h @@ -27,17 +27,13 @@ #include "ardour/session_handle.h" -#ifndef TICKER_H_ -#define TICKER_H_ +#ifndef __libardour_ticker_h__ +#define __libardour_ticker_h__ -namespace MIDI { - class Port; -} - -namespace ARDOUR -{ +namespace ARDOUR { class Session; +class MidiPort; class MidiClockTicker : public SessionHandlePtr, boost::noncopyable { @@ -45,7 +41,7 @@ public: MidiClockTicker (); virtual ~MidiClockTicker(); - void tick (const framepos_t& transport_frames); + void tick (const framepos_t& transport_frames, pframes_t nframes); bool has_midi_port() const { return _midi_port != 0; } @@ -58,9 +54,6 @@ public: /// slot for the signal session::TransportStateChange void transport_state_changed(); - /// slot for the signal session::PositionChanged - void position_changed (framepos_t position); - /// slot for the signal session::TransportLooped void transport_looped(); @@ -70,23 +63,25 @@ public: /// pulses per quarter note (default 24) void set_ppqn(int ppqn) { _ppqn = ppqn; } -private: - MIDI::Port* _midi_port; - int _ppqn; - double _last_tick; - - class Position; - boost::scoped_ptr _pos; - - double one_ppqn_in_frames (framepos_t transport_position); - - void send_midi_clock_event (pframes_t offset); - void send_start_event (pframes_t offset); - void send_continue_event (pframes_t offset); - void send_stop_event (pframes_t offset); - void send_position_event (uint32_t midi_clocks, pframes_t offset); + private: + boost::shared_ptr _midi_port; + int _ppqn; + double _last_tick; + bool _send_pos; + bool _send_state; + + class Position; + boost::scoped_ptr _pos; + + double one_ppqn_in_frames (framepos_t transport_position); + + void send_midi_clock_event (pframes_t offset, pframes_t nframes); + void send_start_event (pframes_t offset, pframes_t nframes); + void send_continue_event (pframes_t offset, pframes_t nframes); + void send_stop_event (pframes_t offset, pframes_t nframes); + void send_position_event (uint32_t midi_clocks, pframes_t offset, pframes_t nframes); }; - } + // namespace -#endif /* TICKER_H_ */ +#endif /* __libardour_ticker_h__ */ diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 0c88e7c0fd..9c04529384 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -37,10 +37,9 @@ #include #include "midi++/port.h" -#include "midi++/jack_midi_port.h" #include "midi++/mmc.h" -#include "midi++/manager.h" +#include "ardour/async_midi_port.h" #include "ardour/audio_port.h" #include "ardour/audio_backend.h" #include "ardour/audioengine.h" @@ -50,6 +49,7 @@ #include "ardour/internal_send.h" #include "ardour/meter.h" #include "ardour/midi_port.h" +#include "ardour/midiport_manager.h" #include "ardour/port.h" #include "ardour/process_thread.h" #include "ardour/session.h" @@ -66,10 +66,11 @@ AudioEngine* AudioEngine::_instance = 0; AudioEngine::AudioEngine () : session_remove_pending (false) , session_removal_countdown (-1) + , _running (false) + , _freewheeling (false) , monitor_check_interval (INT32_MAX) , last_monitor_check (0) , _processed_frames (0) - , _freewheeling (false) , _pre_freewheel_mmc_enabled (false) , m_meter_thread (0) , _main_thread (0) @@ -117,7 +118,7 @@ _thread_init_callback (void * /*arg*/) SessionEvent::create_per_thread_pool (X_("Audioengine"), 512); - MIDI::JackMIDIPort::set_process_thread (pthread_self()); + AsyncMIDIPort::set_process_thread (pthread_self()); } void @@ -231,8 +232,8 @@ AudioEngine::process_callback (pframes_t nframes) if (_session == 0) { if (!_freewheeling) { - MIDI::Manager::instance()->cycle_start(nframes); - MIDI::Manager::instance()->cycle_end(); + PortManager::cycle_start (nframes); + PortManager::cycle_end (nframes); } _processed_frames = next_processed_frames; @@ -243,34 +244,22 @@ AudioEngine::process_callback (pframes_t nframes) /* tell all relevant objects that we're starting a new cycle */ InternalSend::CycleStart (nframes); - Port::set_global_port_buffer_offset (0); - Port::set_cycle_framecnt (nframes); /* tell all Ports that we're starting a new cycle */ - boost::shared_ptr p = ports.reader(); - - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - i->second->cycle_start (nframes); - } + PortManager::cycle_start (nframes); /* test if we are freewheeling and there are freewheel signals connected. ardour should act normally even when freewheeling unless /it/ is - exporting + exporting (which is what Freewheel.empty() tests for). */ if (_freewheeling && !Freewheel.empty()) { - Freewheel (nframes); - } else { - MIDI::Manager::instance()->cycle_start(nframes); - if (_session) { _session->process (nframes); } - - MIDI::Manager::instance()->cycle_end(); } if (_freewheeling) { @@ -283,52 +272,18 @@ AudioEngine::process_callback (pframes_t nframes) } if (last_monitor_check + monitor_check_interval < next_processed_frames) { - - boost::shared_ptr p = ports.reader(); - - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - - bool x; - - if (i->second->last_monitor() != (x = i->second->monitoring_input ())) { - i->second->set_last_monitor (x); - /* XXX I think this is dangerous, due to - a likely mutex in the signal handlers ... - */ - i->second->MonitorInputChanged (x); /* EMIT SIGNAL */ - } - } + + PortManager::check_monitoring (); last_monitor_check = next_processed_frames; } if (_session->silent()) { - - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - - if (i->second->sends_output()) { - i->second->get_buffer(nframes).silence(nframes); - } - } + PortManager::silence (nframes); } if (session_remove_pending && session_removal_countdown) { - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - - if (i->second->sends_output()) { - - boost::shared_ptr ap = boost::dynamic_pointer_cast (i->second); - if (ap) { - Sample* s = ap->engine_get_whole_audio_buffer (); - gain_t g = session_removal_gain; - - for (pframes_t n = 0; n < nframes; ++n) { - *s++ *= g; - g -= session_removal_gain_step; - } - } - } - } + PortManager::fade_out (session_removal_gain, session_removal_gain_step, nframes); if (session_removal_countdown > nframes) { session_removal_countdown -= nframes; @@ -339,11 +294,7 @@ AudioEngine::process_callback (pframes_t nframes) session_removal_gain -= (nframes * session_removal_gain_step); } - // Finalize ports - - for (Ports::iterator i = p->begin(); i != p->end(); ++i) { - i->second->cycle_end (nframes); - } + PortManager::cycle_end (nframes); _processed_frames = next_processed_frames; @@ -574,7 +525,7 @@ AudioEngine::set_backend (const std::string& name, const std::string& arg1, cons } drop_backend (); - + try { cerr << "Instantiate " << b->second->name << " with " << arg1 << " + " << arg2 << endl; @@ -603,31 +554,45 @@ AudioEngine::start () return -1; } - if (!_running) { + if (_running) { + return 0; + } - if (_session) { - BootMessage (_("Connect session to engine")); - _session->set_frame_rate (_backend->sample_rate()); - } + /* if we're still connected (i.e. previously paused), no need to + * re-register ports. + */ + + bool have_ports = (!ports.reader()->empty()); - _processed_frames = 0; - last_monitor_check = 0; + _processed_frames = 0; + last_monitor_check = 0; + + if (_backend->start() == 0) { - if (_backend->start() == 0) { - _running = true; - last_monitor_check = 0; + _running = true; + last_monitor_check = 0; + + if (_session) { + _session->set_frame_rate (_backend->sample_rate()); - if (_session && _session->config.get_jack_time_master()) { + if (_session->config.get_jack_time_master()) { _backend->set_time_master (true); } - - Running(); /* EMIT SIGNAL */ - } else { - /* should report error? */ } - } - return _running ? 0 : -1; + if (!have_ports) { + PortManager::create_ports (); + } + + _mmc.set_ports (mmc_input_port(), mmc_output_port()); + + Running(); /* EMIT SIGNAL */ + + return 0; + } + + /* should report error ... */ + return -1; } int @@ -641,6 +606,7 @@ AudioEngine::stop () if (_backend->stop () == 0) { _running = false; + _processed_frames = 0; stop_metering_thread (); Stopped (); /* EMIT SIGNAL */ @@ -932,7 +898,7 @@ AudioEngine::thread_init_callback (void* arg) SessionEvent::create_per_thread_pool (X_("AudioEngine"), 512); - MIDI::JackMIDIPort::set_process_thread (pthread_self()); + AsyncMIDIPort::set_process_thread (pthread_self()); if (arg) { AudioEngine* ae = static_cast (arg); @@ -964,10 +930,10 @@ void AudioEngine::freewheel_callback (bool onoff) { if (onoff) { - _pre_freewheel_mmc_enabled = MIDI::Manager::instance()->mmc()->send_enabled (); - MIDI::Manager::instance()->mmc()->enable_send (false); + _pre_freewheel_mmc_enabled = _mmc.send_enabled (); + _mmc.enable_send (false); } else { - MIDI::Manager::instance()->mmc()->enable_send (_pre_freewheel_mmc_enabled); + _mmc.enable_send (_pre_freewheel_mmc_enabled); } } @@ -991,8 +957,6 @@ void AudioEngine::halted_callback (const char* why) { stop_metering_thread (); - - MIDI::JackMIDIPort::EngineHalted (); /* EMIT SIGNAL */ Halted (why); /* EMIT SIGNAL */ } diff --git a/libs/ardour/debug.cc b/libs/ardour/debug.cc index afd5da2169..fb122dd83c 100644 --- a/libs/ardour/debug.cc +++ b/libs/ardour/debug.cc @@ -60,5 +60,6 @@ uint64_t PBD::DEBUG::TempoMap = PBD::new_debug_bit ("tempomap"); uint64_t PBD::DEBUG::OrderKeys = PBD::new_debug_bit ("orderkeys"); uint64_t PBD::DEBUG::Automation = PBD::new_debug_bit ("automation"); uint64_t PBD::DEBUG::WiimoteControl = PBD::new_debug_bit ("wiimotecontrol"); +uint64_t PBD::DEBUG::Ports = PBD::new_debug_bit ("Ports"); diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index d744368fe7..fbce336283 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -67,7 +67,6 @@ #include "pbd/basename.h" #include "midi++/port.h" -#include "midi++/manager.h" #include "midi++/mmc.h" #include "ardour/analyser.h" @@ -80,6 +79,7 @@ #include "ardour/control_protocol_manager.h" #include "ardour/filesystem_paths.h" #include "ardour/midi_region.h" +#include "ardour/midiport_manager.h" #include "ardour/mix.h" #include "ardour/panner_manager.h" #include "ardour/plugin_manager.h" @@ -340,9 +340,6 @@ ARDOUR::init (bool use_windows_vst, bool try_optimization, const char* localedir void ARDOUR::init_post_engine () { - /* the MIDI Manager is needed by the ControlProtocolManager */ - MIDI::Manager::create (AudioEngine::instance()->port_engine()); - ControlProtocolManager::instance().discover_control_protocols (); XMLNode* node; diff --git a/libs/ardour/jack_audiobackend.cc b/libs/ardour/jack_audiobackend.cc index 19158aacc9..2e0d90202f 100644 --- a/libs/ardour/jack_audiobackend.cc +++ b/libs/ardour/jack_audiobackend.cc @@ -24,7 +24,8 @@ #include "pbd/error.h" -#include "midi++/manager.h" +#include "jack/jack.h" +#include "jack/thread.h" #include "ardour/audioengine.h" #include "ardour/types.h" @@ -57,6 +58,7 @@ JACKAudioBackend::JACKAudioBackend (AudioEngine& e, boost::shared_ptrDisconnected.connect_same_thread (disconnect_connection, boost::bind (&JACKAudioBackend::disconnected, this, _1)); } JACKAudioBackend::~JACKAudioBackend() @@ -897,8 +899,6 @@ JACKAudioBackend::jack_bufsize_callback (pframes_t nframes) void JACKAudioBackend::disconnected (const char* why) { - /* called from jack shutdown handler */ - bool was_running = _running; _running = false; diff --git a/libs/ardour/jack_connection.cc b/libs/ardour/jack_connection.cc index 57950b0e17..d48e3355b5 100644 --- a/libs/ardour/jack_connection.cc +++ b/libs/ardour/jack_connection.cc @@ -135,7 +135,10 @@ JackConnection::close () GET_PRIVATE_JACK_POINTER_RET (_jack, -1); if (_priv_jack) { - return jack_client_close (_priv_jack); + int ret = jack_client_close (_priv_jack); + _jack = 0; + Disconnected (""); /* EMIT SIGNAL */ + return ret; } return 0; diff --git a/libs/ardour/ladspa_plugin.cc b/libs/ardour/ladspa_plugin.cc index 5a6e577f2d..6a2636e4f4 100644 --- a/libs/ardour/ladspa_plugin.cc +++ b/libs/ardour/ladspa_plugin.cc @@ -36,8 +36,6 @@ #include "pbd/xml++.h" #include "pbd/stacktrace.h" -#include "midi++/manager.h" - #include "ardour/session.h" #include "ardour/ladspa_plugin.h" #include "ardour/buffer_set.h" diff --git a/libs/ardour/midi_clock_slave.cc b/libs/ardour/midi_clock_slave.cc index 6f54d17d02..752644e9f4 100644 --- a/libs/ardour/midi_clock_slave.cc +++ b/libs/ardour/midi_clock_slave.cc @@ -31,6 +31,8 @@ #include "midi++/port.h" #include "ardour/debug.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_port.h" #include "ardour/slave.h" #include "ardour/tempo.h" @@ -41,13 +43,20 @@ using namespace ARDOUR; using namespace MIDI; using namespace PBD; -MIDIClock_Slave::MIDIClock_Slave (Session& s, MIDI::Port& p, int ppqn) +MIDIClock_Slave::MIDIClock_Slave (Session& s, MidiPort& p, int ppqn) : ppqn (ppqn) , bandwidth (10.0 / 60.0) // 1 BpM = 1 / 60 Hz { session = (ISlaveSessionProxy *) new SlaveSessionProxy(s); rebind (p); reset (); + + parser.timing.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::update_midi_clock, this, _1, _2)); + parser.start.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::start, this, _1, _2)); + parser.contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::contineu, this, _1, _2)); + parser.stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::stop, this, _1, _2)); + parser.position.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::position, this, _1, _2, 3)); + } MIDIClock_Slave::MIDIClock_Slave (ISlaveSessionProxy* session_proxy, int ppqn) @@ -63,20 +72,33 @@ MIDIClock_Slave::~MIDIClock_Slave() delete session; } -void -MIDIClock_Slave::rebind (MIDI::Port& p) +int +MIDIClock_Slave::process (pframes_t nframes) { - port_connections.drop_connections(); + MidiBuffer& mb (port->get_midi_buffer (nframes)); - port = &p; + /* dump incoming MIDI to parser */ - DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MIDIClock_Slave: connecting to port %1\n", port->name())); + for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) { + uint8_t* buf = (*b).buffer(); + + parser.set_timestamp ((*b).time()); - port->parser()->timing.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::update_midi_clock, this, _1, _2)); - port->parser()->start.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::start, this, _1, _2)); - port->parser()->contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::contineu, this, _1, _2)); - port->parser()->stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::stop, this, _1, _2)); - port->parser()->position.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::position, this, _1, _2, 3)); + uint32_t limit = (*b).size(); + + for (size_t n = 0; n < limit; ++n) { + parser.scanner (buf[n]); + } + } + + return 0; +} + +void +MIDIClock_Slave::rebind (MidiPort& p) +{ + port = &p; + DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MIDIClock_Slave: connecting to port %1\n", port->name())); } void diff --git a/libs/ardour/midi_ui.cc b/libs/ardour/midi_ui.cc index 0d9ac17601..e75c05c593 100644 --- a/libs/ardour/midi_ui.cc +++ b/libs/ardour/midi_ui.cc @@ -22,11 +22,11 @@ #include "pbd/pthread_utils.h" -#include "midi++/manager.h" -#include "midi++/port.h" - +#include "ardour/async_midi_port.h" #include "ardour/debug.h" #include "ardour/audioengine.h" +#include "ardour/midi_port.h" +#include "ardour/midiport_manager.h" #include "ardour/midi_ui.h" #include "ardour/session.h" #include "ardour/session_event.h" @@ -48,7 +48,6 @@ MidiControlUI::MidiControlUI (Session& s) : AbstractUI (X_("midiui")) , _session (s) { - MIDI::Manager::instance()->PortsChanged.connect_same_thread (rebind_connection, boost::bind (&MidiControlUI::change_midi_ports, this)); _instance = this; } @@ -83,20 +82,10 @@ MidiControlUI::do_request (MidiUIRequest* req) } } -void -MidiControlUI::change_midi_ports () -{ - MidiUIRequest* req = get_request (PortChange); - if (req == 0) { - return; - } - send_request (req); -} - bool -MidiControlUI::midi_input_handler (IOCondition ioc, MIDI::Port* port) +MidiControlUI::midi_input_handler (IOCondition ioc, AsyncMIDIPort* port) { - DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", port->name())); + DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", ((ARDOUR::Port*)port)->name())); if (ioc & ~IO_IN) { return false; @@ -106,7 +95,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())); + DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", ((ARDOUR::Port*)port)->name())); framepos_t now = _session.engine().sample_time(); port->parse (now); } @@ -128,22 +117,19 @@ MidiControlUI::clear_ports () void MidiControlUI::reset_ports () { - clear_ports (); - - boost::shared_ptr plist = MIDI::Manager::instance()->get_midi_ports (); + if (port_sources.empty()) { + AsyncMIDIPort* async = dynamic_cast (AudioEngine::instance()->midi_input_port()); - for (MIDI::Manager::PortList::const_iterator i = plist->begin(); i != plist->end(); ++i) { - - if (!(*i)->centrally_parsed()) { - continue; + if (!async) { + return; } int fd; - if ((fd = (*i)->selectable ()) >= 0) { + if ((fd = async->selectable ()) >= 0) { Glib::RefPtr psrc = IOSource::create (fd, IO_IN|IO_HUP|IO_ERR); - - psrc->connect (sigc::bind (sigc::mem_fun (this, &MidiControlUI::midi_input_handler), *i)); + + psrc->connect (sigc::bind (sigc::mem_fun (this, &MidiControlUI::midi_input_handler), async)); psrc->attach (_main_loop->get_context()); // glibmm hack: for now, store only the GSource* diff --git a/libs/ardour/midiport_manager.cc b/libs/ardour/midiport_manager.cc index fb27800762..ec525fd9f8 100644 --- a/libs/ardour/midiport_manager.cc +++ b/libs/ardour/midiport_manager.cc @@ -66,11 +66,47 @@ MidiPortManager::port (string const & n) void MidiPortManager::create_ports () { - _midi_in = AudioEngine::instance()->register_input_port (DataType::MIDI, _("MIDI control in"), true); - _midi_out = AudioEngine::instance()->register_output_port (DataType::MIDI, _("MIDI control out"), true); + /* this method is idempotent + */ + + if (_midi_in) { + return; + } + + _midi_in = AudioEngine::instance()->register_input_port (DataType::MIDI, _("control in"), true); + _midi_out = AudioEngine::instance()->register_output_port (DataType::MIDI, _("control out"), true); + + _mmc_in = AudioEngine::instance()->register_input_port (DataType::MIDI, _("mmc in"), true); + _mmc_out = AudioEngine::instance()->register_output_port (DataType::MIDI, _("mmc out"), true); + /* XXX nasty type conversion needed because of the mixed inheritance + * required to integrate MIDI::IPMidiPort and ARDOUR::AsyncMIDIPort. + * + * At some point, we'll move IPMidiPort into Ardour and make it + * inherit from ARDOUR::MidiPort not MIDI::Port, and then this + * mess can go away + */ + _midi_input_port = boost::dynamic_pointer_cast(_midi_in).get(); _midi_output_port = boost::dynamic_pointer_cast(_midi_out).get(); + + _mmc_input_port = boost::dynamic_pointer_cast(_mmc_in).get(); + _mmc_output_port = boost::dynamic_pointer_cast(_mmc_out).get(); + + /* Now register ports used for sync (MTC and MIDI Clock) + */ + + boost::shared_ptr p; + + p = AudioEngine::instance()->register_input_port (DataType::MIDI, _("timecode in")); + _mtc_input_port = boost::dynamic_pointer_cast (p); + p = AudioEngine::instance()->register_output_port (DataType::MIDI, _("timecode out")); + _mtc_output_port= boost::dynamic_pointer_cast (p); + + p = AudioEngine::instance()->register_input_port (DataType::MIDI, _("clock in")); + _midi_clock_input_port = boost::dynamic_pointer_cast (p); + p = AudioEngine::instance()->register_output_port (DataType::MIDI, _("clock out")); + _midi_clock_output_port= boost::dynamic_pointer_cast (p); } void diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index 0f2761c350..b42b4989d2 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -25,11 +25,12 @@ #include "pbd/error.h" -#include "midi++/port.h" +#include "ardour/audioengine.h" #include "ardour/debug.h" -#include "ardour/slave.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_port.h" #include "ardour/session.h" -#include "ardour/audioengine.h" +#include "ardour/slave.h" #include "i18n.h" @@ -48,8 +49,9 @@ using namespace Timecode; */ const int MTC_Slave::frame_tolerance = 2; -MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p) +MTC_Slave::MTC_Slave (Session& s, MidiPort& p) : session (s) + , port (&p) { can_notify_on_unknown_rate = true; did_reset_tc_format = false; @@ -70,7 +72,11 @@ MTC_Slave::MTC_Slave (Session& s, MIDI::Port& p) session.config.ParameterChanged.connect_same_thread (config_connection, boost::bind (&MTC_Slave::parameter_changed, this, _1)); parse_timecode_offset(); reset (true); - rebind (p); + + parser.mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3)); + parser.mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3)); + parser.mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1)); + } MTC_Slave::~MTC_Slave() @@ -93,16 +99,35 @@ MTC_Slave::~MTC_Slave() } } +int +MTC_Slave::process (pframes_t nframes) +{ + MidiBuffer& mb (port->get_midi_buffer (nframes)); + + /* dump incoming MIDI to parser */ + + for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) { + uint8_t* buf = (*b).buffer(); + + parser.set_timestamp ((*b).time()); + + uint32_t limit = (*b).size(); + + for (size_t n = 0; n < limit; ++n) { + parser.scanner (buf[n]); + } + } + + return 0; +} + void -MTC_Slave::rebind (MIDI::Port& p) +MTC_Slave::rebind (MidiPort& p) { port_connections.drop_connections (); port = &p; - port->parser()->mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3)); - port->parser()->mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3)); - port->parser()->mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1)); } void @@ -154,7 +179,7 @@ MTC_Slave::outside_window (framepos_t pos) const bool MTC_Slave::locked () const { - return port->parser()->mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0; + return parser.mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0; } bool @@ -446,7 +471,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now) DEBUG_TRACE (DEBUG::MTC, string_compose ("new mtc_frame: %1 | MTC-FpT: %2 A3-FpT:%3\n", mtc_frame, (4.0*qtr), session.frames_per_timecode_frame())); - switch (port->parser()->mtc_running()) { + switch (parser.mtc_running()) { case MTC_Backward: mtc_frame -= mtc_off; qtr *= -1.0; @@ -528,7 +553,7 @@ MTC_Slave::reset_window (framepos_t root) */ framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance); - switch (port->parser()->mtc_running()) { + switch (parser.mtc_running()) { case MTC_Forward: window_begin = root; transport_direction = 1; diff --git a/libs/ardour/port.cc b/libs/ardour/port.cc index 571d227711..7dc11c6d3d 100644 --- a/libs/ardour/port.cc +++ b/libs/ardour/port.cc @@ -390,6 +390,7 @@ Port::get_connected_latency_range (LatencyRange& range, bool playback) const int Port::reestablish () { + DEBUG_TRACE (DEBUG::Ports, string_compose ("re-establish %1 port %2\n", type().to_string(), _name)); _port_handle = port_engine.register_port (_name, type(), _flags); if (_port_handle == 0) { diff --git a/libs/ardour/port_manager.cc b/libs/ardour/port_manager.cc index 5c807a6979..41331fe3a5 100644 --- a/libs/ardour/port_manager.cc +++ b/libs/ardour/port_manager.cc @@ -19,11 +19,12 @@ #include "pbd/error.h" -#include "midi++/manager.h" - +#include "ardour/async_midi_port.h" +#include "ardour/debug.h" #include "ardour/port_manager.h" #include "ardour/audio_port.h" #include "ardour/midi_port.h" +#include "ardour/midiport_manager.h" #include "i18n.h" @@ -227,6 +228,18 @@ PortManager::port_renamed (const std::string& old_relative_name, const std::stri } } +int +PortManager::get_ports (DataType type, PortList& pl) +{ + boost::shared_ptr plist = ports.reader(); + for (Ports::iterator p = plist->begin(); p != plist->end(); ++p) { + if (p->second->type() == type) { + pl.push_back (p->second); + } + } + return pl.size(); +} + int PortManager::get_ports (const string& port_name_pattern, DataType type, PortFlags flags, vector& s) { @@ -262,15 +275,25 @@ PortManager::port_registration_failure (const std::string& portname) } boost::shared_ptr -PortManager::register_port (DataType dtype, const string& portname, bool input) +PortManager::register_port (DataType dtype, const string& portname, bool input, bool async) { boost::shared_ptr newport; try { if (dtype == DataType::AUDIO) { + DEBUG_TRACE (DEBUG::Ports, string_compose ("registering AUDIO port %1, input %2\n", + portname, input)); newport.reset (new AudioPort (portname, (input ? IsInput : IsOutput))); } else if (dtype == DataType::MIDI) { - newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput))); + if (async) { + DEBUG_TRACE (DEBUG::Ports, string_compose ("registering ASYNC MIDI port %1, input %2\n", + portname, input)); + newport.reset (new AsyncMIDIPort (portname, (input ? IsInput : IsOutput))); + } else { + DEBUG_TRACE (DEBUG::Ports, string_compose ("registering MIDI port %1, input %2\n", + portname, input)); + newport.reset (new MidiPort (portname, (input ? IsInput : IsOutput))); + } } else { throw PortRegistrationFailure("unable to create port (unknown type)"); } @@ -281,7 +304,6 @@ PortManager::register_port (DataType dtype, const string& portname, bool input) /* writer goes out of scope, forces update */ - return newport; } catch (PortRegistrationFailure& err) { @@ -292,18 +314,21 @@ PortManager::register_port (DataType dtype, const string& portname, bool input) } catch (...) { throw PortRegistrationFailure("unable to create port (unknown error)"); } + + DEBUG_TRACE (DEBUG::Ports, string_compose ("\t%2 port registration success, ports now = %1\n", ports.reader()->size(), this)); + return newport; } boost::shared_ptr -PortManager::register_input_port (DataType type, const string& portname) +PortManager::register_input_port (DataType type, const string& portname, bool async) { - return register_port (type, portname, true); + return register_port (type, portname, true, async); } boost::shared_ptr -PortManager::register_output_port (DataType type, const string& portname) +PortManager::register_output_port (DataType type, const string& portname, bool async) { - return register_port (type, portname, false); + return register_port (type, portname, false, async); } int @@ -410,6 +435,8 @@ PortManager::reestablish_ports () boost::shared_ptr p = ports.reader (); + DEBUG_TRACE (DEBUG::Ports, string_compose ("reestablish %1 ports\n", p->size())); + for (i = p->begin(); i != p->end(); ++i) { if (i->second->reestablish ()) { break; @@ -422,8 +449,6 @@ PortManager::reestablish_ports () return -1; } - MIDI::Manager::instance()->reestablish (); - return 0; } @@ -434,12 +459,12 @@ PortManager::reconnect_ports () /* re-establish connections */ + DEBUG_TRACE (DEBUG::Ports, string_compose ("reconnect %1 ports\n", p->size())); + for (Ports::iterator i = p->begin(); i != p->end(); ++i) { i->second->reconnect (); } - MIDI::Manager::instance()->reconnect (); - return 0; } @@ -543,3 +568,80 @@ PortManager::graph_order_callback () return 0; } + +void +PortManager::cycle_start (pframes_t nframes) +{ + Port::set_global_port_buffer_offset (0); + Port::set_cycle_framecnt (nframes); + + _cycle_ports = ports.reader (); + + for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) { + p->second->cycle_start (nframes); + } +} + +void +PortManager::cycle_end (pframes_t nframes) +{ + for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) { + p->second->cycle_end (nframes); + } + + for (Ports::iterator p = _cycle_ports->begin(); p != _cycle_ports->end(); ++p) { + p->second->flush_buffers (nframes); + } + + _cycle_ports.reset (); + + /* we are done */ +} + +void +PortManager::silence (pframes_t nframes) +{ + for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) { + if (i->second->sends_output()) { + i->second->get_buffer(nframes).silence(nframes); + } + } +} + +void +PortManager::check_monitoring () +{ + for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) { + + bool x; + + if (i->second->last_monitor() != (x = i->second->monitoring_input ())) { + i->second->set_last_monitor (x); + /* XXX I think this is dangerous, due to + a likely mutex in the signal handlers ... + */ + i->second->MonitorInputChanged (x); /* EMIT SIGNAL */ + } + } +} + +void +PortManager::fade_out (gain_t base_gain, gain_t gain_step, pframes_t nframes) +{ + for (Ports::iterator i = _cycle_ports->begin(); i != _cycle_ports->end(); ++i) { + + if (i->second->sends_output()) { + + boost::shared_ptr ap = boost::dynamic_pointer_cast (i->second); + if (ap) { + Sample* s = ap->engine_get_whole_audio_buffer (); + gain_t g = base_gain; + + for (pframes_t n = 0; n < nframes; ++n) { + *s++ *= g; + g -= gain_step; + } + } + } + } +} diff --git a/libs/ardour/rc_configuration.cc b/libs/ardour/rc_configuration.cc index 8127267975..007d6041db 100644 --- a/libs/ardour/rc_configuration.cc +++ b/libs/ardour/rc_configuration.cc @@ -27,13 +27,12 @@ #include "pbd/xml++.h" #include "pbd/file_utils.h" -#include "midi++/manager.h" - #include "ardour/control_protocol_manager.h" #include "ardour/diskstream.h" #include "ardour/filesystem_paths.h" #include "ardour/rc_configuration.h" #include "ardour/session_metadata.h" +#include "ardour/midiport_manager.h" #include "i18n.h" @@ -177,15 +176,20 @@ RCConfiguration::get_state () root = new XMLNode("Ardour"); - MIDI::Manager* mm = MIDI::Manager::instance(); + /* XXX + * GET STATE OF MIDI::Port HERE + */ +#if 0 + MidiPortManager* mm = MidiPortManager::instance(); if (mm) { - boost::shared_ptr ports = mm->get_midi_ports(); + boost::shared_ptr ports = mm->get_midi_ports(); - for (MIDI::Manager::PortList::const_iterator i = ports->begin(); i != ports->end(); ++i) { - root->add_child_nocopy((*i)->get_state()); + for (MidiPortManager::PortList::const_iterator i = ports->begin(); i != ports->end(); ++i) { + // root->add_child_nocopy ((*i)->get_state()); } } +#endif root->add_child_nocopy (get_variables ()); diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 9667bbcd2c..cc4a99b11f 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -49,6 +49,7 @@ #include "ardour/amp.h" #include "ardour/analyser.h" +#include "ardour/async_midi_port.h" #include "ardour/audio_buffer.h" #include "ardour/audio_diskstream.h" #include "ardour/audio_port.h" @@ -66,6 +67,7 @@ #include "ardour/debug.h" #include "ardour/filename_extensions.h" #include "ardour/graph.h" +#include "ardour/midiport_manager.h" #include "ardour/midi_track.h" #include "ardour/midi_ui.h" #include "ardour/operations.h" @@ -88,9 +90,7 @@ #include "ardour/utils.h" #include "midi++/port.h" -#include "midi++/jack_midi_port.h" #include "midi++/mmc.h" -#include "midi++/manager.h" #include "i18n.h" @@ -584,7 +584,8 @@ Session::when_engine_running () as it will set states for ports which the ControlProtocolManager creates. */ - MIDI::Manager::instance()->set_port_states (Config->midi_port_states ()); + // XXX set state of MIDI::Port's + // MidiPortManager::instance()->set_port_states (Config->midi_port_states ()); /* And this must be done after the MIDI::Manager::set_port_states as * it will try to make connections whose details are loaded by set_port_states. @@ -874,7 +875,12 @@ Session::hookup_io () /* Tell all IO objects to connect themselves together */ IO::enable_connecting (); - MIDI::JackMIDIPort::MakeConnections (); + + /* Now tell all "floating" ports to connect to whatever + they should be connected to. + */ + + AudioEngine::instance()->reconnect_ports (); /* Anyone who cares about input state, wake up and do something */ @@ -1169,7 +1175,7 @@ Session::enable_record () if (g_atomic_int_compare_and_exchange (&_record_status, rs, Recording)) { _last_record_location = _transport_frame; - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordStrobe)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordStrobe)); if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) { set_track_monitor_input_status (true); @@ -1190,7 +1196,7 @@ Session::disable_record (bool rt_context, bool force) if ((!Config->get_latched_record_enable () && !play_loop) || force) { g_atomic_int_set (&_record_status, Disabled); - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit)); } else { if (rs == Recording) { g_atomic_int_set (&_record_status, Enabled); @@ -1244,7 +1250,7 @@ Session::maybe_enable_record () enable_record (); } } else { - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordPause)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordPause)); RecordStateChanged (); /* EMIT SIGNAL */ } diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index 0db4fc33bb..ab37e915bf 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -21,7 +21,6 @@ #include "pbd/error.h" #include -#include #include #include "ardour/audioengine.h" @@ -93,8 +92,8 @@ Session::pre_export () /* disable MMC output early */ - _pre_export_mmc_enabled = MIDI::Manager::instance()->mmc()->send_enabled (); - MIDI::Manager::instance()->mmc()->enable_send (false); + _pre_export_mmc_enabled = AudioEngine::instance()->mmc().send_enabled (); + AudioEngine::instance()->mmc().enable_send (false); return 0; } @@ -237,7 +236,7 @@ Session::finalize_audio_export () export_freewheel_connection.disconnect(); - MIDI::Manager::instance()->mmc()->enable_send (_pre_export_mmc_enabled); + AudioEngine::instance()->mmc().enable_send (_pre_export_mmc_enabled); /* maybe write CUE/TOC */ diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index d137e5167c..07a34283e3 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -31,7 +31,6 @@ #include "midi++/mmc.h" #include "midi++/port.h" -#include "midi++/manager.h" #include "pbd/error.h" #include "pbd/pthread_utils.h" @@ -41,6 +40,7 @@ #include "ardour/audio_track.h" #include "ardour/audioengine.h" #include "ardour/debug.h" +#include "ardour/midi_port.h" #include "ardour/midi_track.h" #include "ardour/midi_ui.h" #include "ardour/session.h" @@ -349,7 +349,7 @@ Session::mmc_record_enable (MIDI::MachineControl &mmc, size_t trk, bool enabled) * @param t time to send. */ int -Session::send_full_time_code (framepos_t const t) +Session::send_full_time_code (framepos_t const t, pframes_t nframes) { /* This function could easily send at a given frame offset, but would * that be useful? Does ardour do sub-block accurate locating? [DR] */ @@ -424,10 +424,9 @@ Session::send_full_time_code (framepos_t const t) msg[8] = timecode.frames; // Send message at offset 0, sent time is for the start of this cycle - if (MIDI::Manager::instance()->mtc_output_port()->midimsg (msg, sizeof (msg), 0)) { - error << _("Session: could not send full MIDI time code") << endmsg; - return -1; - } + + MidiBuffer& mb (AudioEngine::instance()->mtc_output_port()->get_midi_buffer (nframes)); + mb.push_back (0, sizeof (msg), msg); _pframes_since_last_mtc = 0; return 0; @@ -470,7 +469,7 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f next_quarter_frame_to_send, quarter_frame_duration)); if (rint(outbound_mtc_timecode_frame + (next_quarter_frame_to_send * quarter_frame_duration)) < _transport_frame) { - send_full_time_code (_transport_frame); + send_full_time_code (_transport_frame, nframes); return 0; } @@ -516,9 +515,10 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f pframes_t const out_stamp = (msg_time - start_frame) / _transport_speed; assert (out_stamp < nframes); - if (MIDI::Manager::instance()->mtc_output_port()->midimsg (mtc_msg, 2, out_stamp)) { + MidiBuffer& mb (AudioEngine::instance()->mtc_output_port()->get_midi_buffer(nframes)); + if (!mb.push_back (out_stamp, 2, mtc_msg)) { error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno)) - << endmsg; + << endmsg; return -1; } @@ -588,7 +588,7 @@ Session::mmc_step_timeout () void -Session::send_song_position_pointer (framepos_t t) +Session::send_song_position_pointer (framepos_t) { if (midi_clock) { /* Do nothing for the moment */ diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index cecbd88f65..6a24198bec 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -40,7 +40,6 @@ #include "ardour/ticker.h" #include "ardour/types.h" -#include "midi++/manager.h" #include "midi++/mmc.h" #include "i18n.h" @@ -85,7 +84,7 @@ Session::process (pframes_t nframes) try { if (!_engine.freewheeling() && Config->get_send_midi_clock() && transport_speed() == 1.0f && midi_clock->has_midi_port()) { - midi_clock->tick (transport_at_start); + midi_clock->tick (transport_at_start, nframes); } } catch (...) { /* don't bother with a message */ @@ -325,7 +324,7 @@ Session::process_with_events (pframes_t nframes) * and prepare for rolling) */ if (_send_timecode_update) { - send_full_time_code (_transport_frame); + send_full_time_code (_transport_frame, nframes); } if (!process_can_proceed()) { @@ -492,6 +491,7 @@ Session::follow_slave (pframes_t nframes) goto noroll; } + _slave->process (nframes); _slave->speed_and_position (slave_speed, slave_transport_frame); DEBUG_TRACE (DEBUG::Slave, string_compose ("Slave position %1 speed %2\n", slave_transport_frame, slave_speed)); diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index cae3b9720a..c4522f76e7 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -60,7 +60,6 @@ #include "midi++/mmc.h" #include "midi++/port.h" -#include "midi++/manager.h" #include "evoral/SMF.hpp" @@ -359,11 +358,11 @@ Session::second_stage_init () BootMessage (_("Reset Remote Controls")); - send_full_time_code (0); + // send_full_time_code (0); _engine.transport_locate (0); - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset)); - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (Timecode::Time ())); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (Timecode::Time ())); MIDI::Name::MidiPatchManager::instance().set_session (this); @@ -3429,11 +3428,11 @@ Session::config_changed (std::string p, bool ours) } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") { - MIDI::Manager::instance()->mmc()->set_receive_device_id (Config->get_mmc_receive_device_id()); + AudioEngine::instance()->mmc().set_receive_device_id (Config->get_mmc_receive_device_id()); } else if (p == "mmc-send-id" || p == "mmc-send-device-id") { - MIDI::Manager::instance()->mmc()->set_send_device_id (Config->get_mmc_send_device_id()); + AudioEngine::instance()->mmc().set_send_device_id (Config->get_mmc_send_device_id()); } else if (p == "midi-control") { @@ -3496,7 +3495,7 @@ Session::config_changed (std::string p, bool ours) } else if (p == "send-mmc") { - MIDI::Manager::instance()->mmc()->enable_send (Config->get_send_mmc ()); + AudioEngine::instance()->mmc().enable_send (Config->get_send_mmc ()); } else if (p == "midi-feedback") { @@ -3554,13 +3553,13 @@ Session::config_changed (std::string p, bool ours) } else if (p == "initial-program-change") { - if (MIDI::Manager::instance()->mmc()->output_port() && Config->get_initial_program_change() >= 0) { + if (AudioEngine::instance()->mmc().output_port() && Config->get_initial_program_change() >= 0) { MIDI::byte buf[2]; buf[0] = MIDI::program; // channel zero by default buf[1] = (Config->get_initial_program_change() & 0x7f); - MIDI::Manager::instance()->mmc()->output_port()->midimsg (buf, sizeof (buf), 0); + AudioEngine::instance()->mmc().output_port()->midimsg (buf, sizeof (buf), 0); } } else if (p == "solo-mute-override") { // catch_up_on_solo_mute_override (); @@ -3624,27 +3623,27 @@ Session::load_diskstreams_2X (XMLNode const & node, int) void Session::setup_midi_machine_control () { - MIDI::MachineControl* mmc = MIDI::Manager::instance()->mmc (); - - mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); - mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); - mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1)); - mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1)); - mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1)); - mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1)); - mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1)); - mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1)); - mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1)); - mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2)); - mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2)); - mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3)); - mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3)); + MIDI::MachineControl& mmc (AudioEngine::instance()->mmc ()); + + mmc.Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); + mmc.DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); + mmc.Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1)); + mmc.FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1)); + mmc.Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1)); + mmc.Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1)); + mmc.RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1)); + mmc.RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1)); + mmc.RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1)); + mmc.Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2)); + mmc.Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2)); + mmc.Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3)); + mmc.TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3)); /* also handle MIDI SPP because its so common */ - mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this)); - mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this)); - mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this)); + mmc.SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this)); + mmc.SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this)); + mmc.SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this)); } boost::shared_ptr diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 08e9a89481..44a885cd1c 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -33,7 +33,6 @@ #include "midi++/mmc.h" #include "midi++/port.h" -#include "midi++/manager.h" #include "ardour/audioengine.h" #include "ardour/auditioner.h" @@ -611,10 +610,11 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) have_looped = false; if (!_engine.freewheeling()) { - send_full_time_code (_transport_frame); + // need to queue this in the next RT cycle + _send_timecode_update = true; if (!dynamic_cast(_slave)) { - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop)); send_mmc_locate (_transport_frame); } } @@ -1260,7 +1260,7 @@ Session::start_transport () Timecode::Time time; timecode_time_subframes (_transport_frame, time); if (!dynamic_cast(_slave)) { - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay)); } } @@ -1338,8 +1338,9 @@ Session::use_sync_source (Slave* new_slave) _slave = new_slave; DEBUG_TRACE (DEBUG::Slave, string_compose ("set new slave to %1\n", _slave)); - - send_full_time_code (_transport_frame); + + // need to queue this for next process() cycle + _send_timecode_update = true; boost::shared_ptr rl = routes.reader(); for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) { @@ -1380,7 +1381,7 @@ Session::switch_to_sync_source (SyncSource src) } try { - new_slave = new MTC_Slave (*this, *MIDI::Manager::instance()->mtc_input_port()); + new_slave = new MTC_Slave (*this, *AudioEngine::instance()->mtc_input_port()); } catch (failed_constructor& err) { @@ -1409,7 +1410,7 @@ Session::switch_to_sync_source (SyncSource src) } try { - new_slave = new MIDIClock_Slave (*this, *MIDI::Manager::instance()->midi_clock_input_port(), 24); + new_slave = new MIDIClock_Slave (*this, *AudioEngine::instance()->midi_clock_input_port(), 24); } catch (failed_constructor& err) { @@ -1636,7 +1637,7 @@ Session::send_mmc_locate (framepos_t t) if (!_engine.freewheeling()) { Timecode::Time time; timecode_time_subframes (t, time); - MIDI::Manager::instance()->mmc()->send (MIDI::MachineControlCommand (time)); + AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (time)); } } diff --git a/libs/ardour/ticker.cc b/libs/ardour/ticker.cc index f32cdf9415..0ed4427b72 100644 --- a/libs/ardour/ticker.cc +++ b/libs/ardour/ticker.cc @@ -19,13 +19,12 @@ #include "pbd/compose.h" #include "pbd/stacktrace.h" -#include "midi++/port.h" -#include "midi++/jack_midi_port.h" -#include "midi++/manager.h" - #include "evoral/midi_events.h" +#include "ardour/async_midi_port.h" #include "ardour/audioengine.h" +#include "ardour/midi_buffer.h" +#include "ardour/midi_port.h" #include "ardour/ticker.h" #include "ardour/session.h" #include "ardour/tempo.h" @@ -95,16 +94,16 @@ public: MidiClockTicker::MidiClockTicker () - : _midi_port (0) - , _ppqn (24) + : _ppqn (24) , _last_tick (0.0) + , _send_pos (false) + , _send_state (false) { _pos.reset (new Position()); } MidiClockTicker::~MidiClockTicker() { - _midi_port = 0; _pos.reset (0); } @@ -115,7 +114,6 @@ MidiClockTicker::set_session (Session* s) if (_session) { _session->TransportStateChange.connect_same_thread (_session_connections, boost::bind (&MidiClockTicker::transport_state_changed, this)); - _session->PositionChanged.connect_same_thread (_session_connections, boost::bind (&MidiClockTicker::position_changed, this, _1)); _session->TransportLooped.connect_same_thread (_session_connections, boost::bind (&MidiClockTicker::transport_looped, this)); _session->Located.connect_same_thread (_session_connections, boost::bind (&MidiClockTicker::session_located, this)); @@ -139,41 +137,20 @@ MidiClockTicker::session_located() return; } - if (_pos->speed == 0.0f) { - uint32_t where = llrint (_pos->midi_beats); - send_position_event (where, 0); - } else if (_pos->speed == 1.0f) { -#if 1 - /* Experimental. To really do this and have accuracy, the - stop/locate/continue sequence would need queued to send immediately - before the next midi clock. */ - - send_stop_event (0); - - if (_pos->frame == 0) { - send_start_event (0); - } else { - uint32_t where = llrint (_pos->midi_beats); - send_position_event (where, 0); - send_continue_event (0); - } -#endif - } else { - /* Varispeed not supported */ - } + _send_pos = true; } void MidiClockTicker::session_going_away () { SessionHandlePtr::session_going_away(); - _midi_port = 0; + _midi_port.reset (); } void MidiClockTicker::update_midi_clock_port() { - _midi_port = MIDI::Manager::instance()->midi_clock_output_port(); + _midi_port = AudioEngine::instance()->midi_clock_output_port(); } void @@ -204,48 +181,11 @@ MidiClockTicker::transport_state_changed() return; } - if (_pos->speed == 1.0f) { - - if (_session->get_play_loop()) { - assert(_session->locations()->auto_loop_location()); - - if (_pos->frame == _session->locations()->auto_loop_location()->start()) { - send_start_event(0); - } else { - send_continue_event(0); - } - - } else if (_pos->frame == 0) { - send_start_event(0); - } else { - send_continue_event(0); - } - - // send_midi_clock_event (0); - - } else if (_pos->speed == 0.0f) { - send_stop_event (0); - send_position_event (llrint (_pos->midi_beats), 0); - } + _send_state = true; // tick (_pos->frame); } -void -MidiClockTicker::position_changed (framepos_t) -{ -#if 0 - const double speed = _session->transport_speed(); - DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Transport Position Change: %1, speed: %2\n", position, speed)); - - if (speed == 0.0f && Config->get_send_midi_clock()) { - send_position_event (position, 0); - } - - _last_tick = position; -#endif -} - void MidiClockTicker::transport_looped() { @@ -270,18 +210,68 @@ MidiClockTicker::transport_looped() } void -MidiClockTicker::tick (const framepos_t& /* transport_frame */) +MidiClockTicker::tick (const framepos_t& /* transport_frame */, pframes_t nframes) { if (!Config->get_send_midi_clock() || _session == 0 || _session->transport_speed() != 1.0f || _midi_port == 0) { return; } - MIDI::JackMIDIPort* mp = dynamic_cast (_midi_port); - if (! mp) { - return; + if (_send_pos) { + if (_pos->speed == 0.0f) { + uint32_t where = llrint (_pos->midi_beats); + send_position_event (where, 0, nframes); + } else if (_pos->speed == 1.0f) { +#if 1 + /* Experimental. To really do this and have accuracy, the + stop/locate/continue sequence would need queued to send immediately + before the next midi clock. */ + + send_stop_event (0, nframes); + + if (_pos->frame == 0) { + send_start_event (0, nframes); + } else { + uint32_t where = llrint (_pos->midi_beats); + send_position_event (where, 0, nframes); + send_continue_event (0, nframes); + } +#endif + } else { + /* Varispeed not supported */ + } + + _send_pos = true; } - const framepos_t end = _pos->frame + mp->nframes_this_cycle(); + if (_send_state) { + if (_pos->speed == 1.0f) { + if (_session->get_play_loop()) { + assert(_session->locations()->auto_loop_location()); + + if (_pos->frame == _session->locations()->auto_loop_location()->start()) { + send_start_event (0, nframes); + } else { + send_continue_event (0, nframes); + } + + } else if (_pos->frame == 0) { + send_start_event (0, nframes); + } else { + send_continue_event (0, nframes); + } + + // send_midi_clock_event (0); + + } else if (_pos->speed == 0.0f) { + send_stop_event (0, nframes); + send_position_event (llrint (_pos->midi_beats), 0, nframes); + } + + _send_state = false; + } + + + const framepos_t end = _pos->frame + nframes; double iter = _last_tick; while (true) { @@ -291,14 +281,14 @@ MidiClockTicker::tick (const framepos_t& /* transport_frame */) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Tick: iter: %1, last tick time: %2, next tick time: %3, offset: %4, cycle length: %5\n", - iter, _last_tick, next_tick, next_tick_offset, mp ? mp->nframes_this_cycle() : 0)); + iter, _last_tick, next_tick, next_tick_offset, nframes)); - if (!mp || (next_tick_offset >= mp->nframes_this_cycle())) { + if (next_tick_offset >= nframes) { break; } if (next_tick_offset >= 0) { - send_midi_clock_event (next_tick_offset); + send_midi_clock_event (next_tick_offset, nframes); } iter = next_tick; @@ -308,7 +298,6 @@ MidiClockTicker::tick (const framepos_t& /* transport_frame */) _pos->frame = end; } - double MidiClockTicker::one_ppqn_in_frames (framepos_t transport_position) { @@ -322,7 +311,7 @@ MidiClockTicker::one_ppqn_in_frames (framepos_t transport_position) } void -MidiClockTicker::send_midi_clock_event (pframes_t offset) +MidiClockTicker::send_midi_clock_event (pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -330,12 +319,13 @@ MidiClockTicker::send_midi_clock_event (pframes_t offset) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Tick with offset %1\n", offset)); - static uint8_t _midi_clock_tick[1] = { MIDI_CMD_COMMON_CLOCK }; - _midi_port->write (_midi_clock_tick, 1, offset); + static uint8_t tick_byte = { MIDI_CMD_COMMON_CLOCK }; + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 1, &tick_byte); } void -MidiClockTicker::send_start_event (pframes_t offset) +MidiClockTicker::send_start_event (pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -343,12 +333,13 @@ MidiClockTicker::send_start_event (pframes_t offset) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Start %1\n", _last_tick)); - static uint8_t _midi_clock_tick[1] = { MIDI_CMD_COMMON_START }; - _midi_port->write (_midi_clock_tick, 1, offset); + static uint8_t tick_byte = { MIDI_CMD_COMMON_START }; + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 1, &tick_byte); } void -MidiClockTicker::send_continue_event (pframes_t offset) +MidiClockTicker::send_continue_event (pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -356,12 +347,13 @@ MidiClockTicker::send_continue_event (pframes_t offset) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Continue %1\n", _last_tick)); - static uint8_t _midi_clock_tick[1] = { MIDI_CMD_COMMON_CONTINUE }; - _midi_port->write (_midi_clock_tick, 1, offset); + static uint8_t tick_byte = { MIDI_CMD_COMMON_CONTINUE }; + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 1, &tick_byte); } void -MidiClockTicker::send_stop_event (pframes_t offset) +MidiClockTicker::send_stop_event (pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -369,12 +361,13 @@ MidiClockTicker::send_stop_event (pframes_t offset) DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Stop %1\n", _last_tick)); - static uint8_t _midi_clock_tick[1] = { MIDI_CMD_COMMON_STOP }; - _midi_port->write (_midi_clock_tick, 1, offset); + static uint8_t tick_byte = { MIDI_CMD_COMMON_STOP }; + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 1, &tick_byte); } void -MidiClockTicker::send_position_event (uint32_t midi_beats, pframes_t offset) +MidiClockTicker::send_position_event (uint32_t midi_beats, pframes_t offset, pframes_t nframes) { if (!_midi_port) { return; @@ -391,7 +384,8 @@ MidiClockTicker::send_position_event (uint32_t midi_beats, pframes_t offset) msg[1] = midi_beats & 0x007f; msg[2] = midi_beats >> 7; - _midi_port->midimsg (msg, sizeof (msg), offset); + MidiBuffer& mb (_midi_port->get_midi_buffer (nframes)); + mb.push_back (offset, 3, &msg[0]); DEBUG_TRACE (DEBUG::MidiClock, string_compose ("Song Position Sent: %1\n", midi_beats)); } diff --git a/libs/ardour/wscript b/libs/ardour/wscript index d48a4d6d85..f13c4e5eef 100644 --- a/libs/ardour/wscript +++ b/libs/ardour/wscript @@ -21,6 +21,7 @@ path_prefix = 'libs/ardour/' libardour_sources = [ 'amp.cc', 'analyser.cc', + 'async_midi_port.cc', 'audio_buffer.cc', 'audio_diskstream.cc', 'audio_library.cc', @@ -126,6 +127,7 @@ libardour_sources = [ 'midi_stretch.cc', 'midi_track.cc', 'midi_ui.cc', + 'midiport_manager.cc', 'mix.cc', 'monitor_processor.cc', 'mtc_slave.cc', diff --git a/libs/midi++2/midi++/mmc.h b/libs/midi++2/midi++/mmc.h index 0f362678ce..01f8bf3b8a 100644 --- a/libs/midi++2/midi++/mmc.h +++ b/libs/midi++2/midi++/mmc.h @@ -38,7 +38,6 @@ namespace MIDI { class Port; class Parser; class MachineControlCommand; -class Manager; /** Class to handle incoming and outgoing MIDI machine control messages */ class MachineControl @@ -95,7 +94,9 @@ class MachineControl cmdResume = 0x7F }; - MachineControl (Manager *, ARDOUR::PortEngine&); + MachineControl (); + + void set_ports (MIDI::Port* input, MIDI::Port* output); Port* input_port() { return _input_port; } Port* output_port() { return _output_port; } diff --git a/libs/midi++2/midi++/parser.h b/libs/midi++2/midi++/parser.h index f5f343e952..44897f9d8e 100644 --- a/libs/midi++2/midi++/parser.h +++ b/libs/midi++2/midi++/parser.h @@ -41,7 +41,7 @@ typedef PBD::Signal3 Signal; class Parser { public: - Parser (Port &p); + Parser (); ~Parser (); /* sets the time that will be reported for any MTC or MIDI Clock @@ -105,7 +105,6 @@ class Parser { const char *midi_event_type_name (MIDI::eventType); void trace (bool onoff, std::ostream *o, const std::string &prefix = ""); bool tracing() { return trace_stream != 0; } - Port &port() { return _port; } void set_offline (bool); bool offline() const { return _offline; } @@ -136,7 +135,6 @@ class Parser { void reset_mtc_state (); private: - Port&_port; /* tracing */ std::ostream *trace_stream; diff --git a/libs/midi++2/midi++/port.h b/libs/midi++2/midi++/port.h index 599fabaa87..6d778beab2 100644 --- a/libs/midi++2/midi++/port.h +++ b/libs/midi++2/midi++/port.h @@ -51,13 +51,6 @@ class Port { virtual XMLNode& get_state () const; virtual void set_state (const XMLNode&); - // FIXME: make Manager a friend of port so these can be hidden? - - /* Only for use by MidiManager. Don't ever call this. */ - virtual void cycle_start (pframes_t) {} - /* Only for use by MidiManager. Don't ever call this. */ - virtual void cycle_end () {} - /** Write a message to port. * @param msg Raw MIDI message to send * @param msglen Size of @a msg diff --git a/libs/midi++2/mmc.cc b/libs/midi++2/mmc.cc index 0a71463721..b93dc0f260 100644 --- a/libs/midi++2/mmc.cc +++ b/libs/midi++2/mmc.cc @@ -27,9 +27,7 @@ #include "midi++/mmc.h" #include "midi++/port.h" -#include "midi++/jack_midi_port.h" #include "midi++/parser.h" -#include "midi++/manager.h" using namespace std; using namespace MIDI; @@ -197,16 +195,21 @@ static void build_mmc_cmd_map () mmc_cmd_map.insert (newpair); } - -MachineControl::MachineControl (Manager* m, ARDOUR::PortEngine& pengine) +MachineControl::MachineControl () { build_mmc_cmd_map (); _receive_device_id = 0x7f; _send_device_id = 0x7f; +} + +void +MachineControl::set_ports (MIDI::Port* ip, MIDI::Port* op) +{ + port_connections.drop_connections (); - _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 = ip; + _output_port = op; _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/parser.cc b/libs/midi++2/parser.cc index 8e3af64504..2f6b50899c 100644 --- a/libs/midi++2/parser.cc +++ b/libs/midi++2/parser.cc @@ -104,8 +104,7 @@ Parser::midi_event_type_name (eventType t) } } -Parser::Parser (Port &p) - : _port(p) +Parser::Parser () { trace_stream = 0; trace_prefix = ""; diff --git a/libs/midi++2/port.cc b/libs/midi++2/port.cc index 3e7896631a..1480202867 100644 --- a/libs/midi++2/port.cc +++ b/libs/midi++2/port.cc @@ -71,7 +71,7 @@ Port::init (string const & name, Flags flags) _tagname = name; _flags = flags; - _parser = new Parser (*this); + _parser = new Parser (); for (int i = 0; i < 16; i++) { _channel[i] = new Channel (i, *this); diff --git a/libs/midi++2/wscript b/libs/midi++2/wscript index 8a4f2f6c69..0abbab7d40 100644 --- a/libs/midi++2/wscript +++ b/libs/midi++2/wscript @@ -31,8 +31,6 @@ libmidi_sources = [ 'midi.cc', 'channel.cc', 'ipmidi_port.cc', - 'jack_midi_port.cc', - 'manager.cc', 'parser.cc', 'port.cc', 'midnam_patch.cc', diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index 6da0192a8f..2820b069dc 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -32,13 +32,14 @@ #include "pbd/xml++.h" #include "midi++/port.h" -#include "midi++/manager.h" +#include "ardour/audioengine.h" #include "ardour/filesystem_paths.h" #include "ardour/session.h" #include "ardour/route.h" #include "ardour/midi_ui.h" #include "ardour/rc_configuration.h" +#include "ardour/midiport_manager.h" #include "generic_midi_control_protocol.h" #include "midicontrollable.h" @@ -59,8 +60,8 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) , _threshold (10) , gui (0) { - _input_port = MIDI::Manager::instance()->midi_input_port (); - _output_port = MIDI::Manager::instance()->midi_output_port (); + _input_port = AudioEngine::instance()->midi_input_port (); + _output_port = AudioEngine::instance()->midi_output_port (); do_feedback = false; _feedback_interval = 10000; // microseconds @@ -338,7 +339,7 @@ GenericMidiControlProtocol::start_learning (Controllable* c) } if (!mc) { - mc = new MIDIControllable (this, *_input_port, *c, false); + mc = new MIDIControllable (this, *_input_port->parser(), *c, false); } { @@ -435,7 +436,7 @@ GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, MIDI::byte value = control_number; // Create a MIDIControllable - MIDIControllable* mc = new MIDIControllable (this, *_input_port, *control, false); + MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *control, false); // Remove any old binding for this midi channel/type/value pair // Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information @@ -559,7 +560,7 @@ GenericMidiControlProtocol::set_state (const XMLNode& node, int version) Controllable* c = Controllable::by_id (id); if (c) { - MIDIControllable* mc = new MIDIControllable (this, *_input_port, *c, false); + MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), *c, false); if (mc->set_state (**niter, version) == 0) { controllables.push_back (mc); @@ -754,7 +755,7 @@ GenericMidiControlProtocol::create_binding (const XMLNode& node) prop = node.property (X_("uri")); uri = prop->value(); - MIDIControllable* mc = new MIDIControllable (this, *_input_port, momentary); + MIDIControllable* mc = new MIDIControllable (this, *_input_port->parser(), momentary); if (mc->init (uri)) { delete mc; @@ -892,7 +893,7 @@ GenericMidiControlProtocol::create_function (const XMLNode& node) prop = node.property (X_("function")); - MIDIFunction* mf = new MIDIFunction (*_input_port); + MIDIFunction* mf = new MIDIFunction (*_input_port->parser()); if (mf->setup (*this, prop->value(), argument, data, data_size)) { delete mf; @@ -988,7 +989,7 @@ GenericMidiControlProtocol::create_action (const XMLNode& node) prop = node.property (X_("action")); - MIDIAction* ma = new MIDIAction (*_input_port); + MIDIAction* ma = new MIDIAction (*_input_port->parser()); if (ma->init (*this, prop->value(), data, data_size)) { delete ma; diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h index a7c420cc41..a4a51b7f99 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.h +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h @@ -22,14 +22,11 @@ #include #include + #include "ardour/types.h" #include "control_protocol/control_protocol.h" -namespace MIDI { - class Port; -} - namespace PBD { class Controllable; class ControllableDescriptor; @@ -37,6 +34,11 @@ namespace PBD { namespace ARDOUR { class Session; + class MidiPort; +} + +namespace MIDI { + class Port; } class MIDIControllable; @@ -51,8 +53,8 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { int set_active (bool yn); static bool probe() { return true; } - MIDI::Port* input_port () const { return _input_port; } - MIDI::Port* output_port () const { return _output_port; } + MIDI::Port* input_port () const { return _input_port; } + MIDI::Port* output_port () const { return _output_port; } void set_feedback_interval (ARDOUR::microseconds_t); int set_feedback (bool yn); @@ -97,8 +99,8 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol { } private: - MIDI::Port* _input_port; - MIDI::Port* _output_port; + MIDI::Port* _input_port; + MIDI::Port* _output_port; ARDOUR::microseconds_t _feedback_interval; ARDOUR::microseconds_t last_feedback_time; diff --git a/libs/surfaces/generic_midi/midiaction.cc b/libs/surfaces/generic_midi/midiaction.cc index e1eed1a49e..e537122e9c 100644 --- a/libs/surfaces/generic_midi/midiaction.cc +++ b/libs/surfaces/generic_midi/midiaction.cc @@ -25,7 +25,7 @@ using namespace MIDI; -MIDIAction::MIDIAction (MIDI::Port& p) +MIDIAction::MIDIAction (MIDI::Parser& p) : MIDIInvokable (p) { } diff --git a/libs/surfaces/generic_midi/midiaction.h b/libs/surfaces/generic_midi/midiaction.h index 521f59f26d..e2a29143ad 100644 --- a/libs/surfaces/generic_midi/midiaction.h +++ b/libs/surfaces/generic_midi/midiaction.h @@ -36,8 +36,6 @@ namespace Gtk { } namespace MIDI { - class Channel; - class Port; class Parser; } @@ -46,7 +44,7 @@ class GenericMidiControlProtocol; class MIDIAction : public MIDIInvokable { public: - MIDIAction (MIDI::Port&); + MIDIAction (MIDI::Parser&); virtual ~MIDIAction (); int init (GenericMidiControlProtocol&, const std::string& action_name, MIDI::byte* sysex = 0, size_t ssize = 0); diff --git a/libs/surfaces/generic_midi/midicontrollable.cc b/libs/surfaces/generic_midi/midicontrollable.cc index d36ccefd44..d78dd5e644 100644 --- a/libs/surfaces/generic_midi/midicontrollable.cc +++ b/libs/surfaces/generic_midi/midicontrollable.cc @@ -27,9 +27,9 @@ #include "pbd/xml++.h" #include "pbd/stacktrace.h" -#include "midi++/port.h" #include "midi++/channel.h" +#include "ardour/async_midi_port.h" #include "ardour/automation_control.h" #include "ardour/midi_ui.h" #include "ardour/utils.h" @@ -42,11 +42,11 @@ using namespace MIDI; using namespace PBD; using namespace ARDOUR; -MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, bool m) +MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, MIDI::Parser& p, bool m) : _surface (s) , controllable (0) , _descriptor (0) - , _port (p) + , _parser (p) , _momentary (m) { _learned = false; /* from URI */ @@ -59,10 +59,10 @@ MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, bool feedback = true; // for now } -MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, Port& p, Controllable& c, bool m) +MIDIControllable::MIDIControllable (GenericMidiControlProtocol* s, MIDI::Parser& p, Controllable& c, bool m) : _surface (s) , _descriptor (0) - , _port (p) + , _parser (p) , _momentary (m) { set_controllable (&c); @@ -149,7 +149,7 @@ void MIDIControllable::learn_about_external_control () { drop_external_control (); - _port.parser()->any.connect_same_thread (midi_learn_connection, boost::bind (&MIDIControllable::midi_receiver, this, _1, _2, _3)); + _parser.any.connect_same_thread (midi_learn_connection, boost::bind (&MIDIControllable::midi_receiver, this, _1, _2, _3)); } void @@ -357,12 +357,6 @@ MIDIControllable::midi_receiver (Parser &, byte *msg, size_t /*len*/) return; } - /* if the our port doesn't do input anymore, forget it ... */ - - if (!_port.parser()) { - return; - } - bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]); if (controllable) { @@ -381,49 +375,43 @@ MIDIControllable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) control_channel = chn; control_additional = additional; - if (_port.parser() == 0) { - return; - } - - Parser& p = *_port.parser(); - int chn_i = chn; switch (ev) { case MIDI::off: - p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); + _parser.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); /* if this is a togglee, connect to noteOn as well, and we'll toggle back and forth between the two. */ if (_momentary) { - p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); + _parser.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); } _control_description = "MIDI control: NoteOff"; break; case MIDI::on: - p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); + _parser.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_note_on, this, _1, _2)); if (_momentary) { - p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); + _parser.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[1], boost::bind (&MIDIControllable::midi_sense_note_off, this, _1, _2)); } _control_description = "MIDI control: NoteOn"; break; case MIDI::controller: - p.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_controller, this, _1, _2)); + _parser.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_controller, this, _1, _2)); snprintf (buf, sizeof (buf), "MIDI control: Controller %d", control_additional); _control_description = buf; break; case MIDI::program: - p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_program_change, this, _1, _2)); + _parser.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_program_change, this, _1, _2)); _control_description = "MIDI control: ProgramChange"; break; case MIDI::pitchbend: - p.channel_pitchbend[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_pitchbend, this, _1, _2)); + _parser.channel_pitchbend[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIControllable::midi_sense_pitchbend, this, _1, _2)); _control_description = "MIDI control: Pitchbend"; break; diff --git a/libs/surfaces/generic_midi/midicontrollable.h b/libs/surfaces/generic_midi/midicontrollable.h index dd9dc988b4..aeed05db4a 100644 --- a/libs/surfaces/generic_midi/midicontrollable.h +++ b/libs/surfaces/generic_midi/midicontrollable.h @@ -36,17 +36,20 @@ namespace PBD { namespace MIDI { class Channel; - class Port; class Parser; } class GenericMidiControlProtocol; +namespace ARDOUR { + class AsyncMIDIPort; +} + class MIDIControllable : public PBD::Stateful { public: - MIDIControllable (GenericMidiControlProtocol *, MIDI::Port&, PBD::Controllable&, bool momentary); - MIDIControllable (GenericMidiControlProtocol *, MIDI::Port&, bool momentary = false); + MIDIControllable (GenericMidiControlProtocol *, MIDI::Parser&, PBD::Controllable&, bool momentary); + MIDIControllable (GenericMidiControlProtocol *, MIDI::Parser&, bool momentary = false); virtual ~MIDIControllable (); int init (const std::string&); @@ -72,7 +75,7 @@ class MIDIControllable : public PBD::Stateful bool learned() const { return _learned; } - MIDI::Port& get_port() const { return _port; } + MIDI::Parser& get_parser() { return _parser; } PBD::Controllable* get_controllable() const { return controllable; } void set_controllable (PBD::Controllable*); const std::string& current_uri() const { return _current_uri; } @@ -98,8 +101,8 @@ class MIDIControllable : public PBD::Stateful GenericMidiControlProtocol* _surface; PBD::Controllable* controllable; PBD::ControllableDescriptor* _descriptor; - std::string _current_uri; - MIDI::Port& _port; + std::string _current_uri; + MIDI::Parser& _parser; bool setting; int last_value; float last_controllable_value; diff --git a/libs/surfaces/generic_midi/midifunction.cc b/libs/surfaces/generic_midi/midifunction.cc index 70e9337861..b0dc95e4fc 100644 --- a/libs/surfaces/generic_midi/midifunction.cc +++ b/libs/surfaces/generic_midi/midifunction.cc @@ -25,7 +25,7 @@ using namespace MIDI; -MIDIFunction::MIDIFunction (MIDI::Port& p) +MIDIFunction::MIDIFunction (MIDI::Parser& p) : MIDIInvokable (p) { } diff --git a/libs/surfaces/generic_midi/midifunction.h b/libs/surfaces/generic_midi/midifunction.h index 8f0b0218d0..88aff0ab0a 100644 --- a/libs/surfaces/generic_midi/midifunction.h +++ b/libs/surfaces/generic_midi/midifunction.h @@ -33,7 +33,6 @@ namespace MIDI { class Channel; - class Port; class Parser; } @@ -64,7 +63,7 @@ class MIDIFunction : public MIDIInvokable TrackSetSoloIsolate, }; - MIDIFunction (MIDI::Port&); + MIDIFunction (MIDI::Parser&); virtual ~MIDIFunction (); int setup (GenericMidiControlProtocol&, const std::string& function_name, const std::string& argument, MIDI::byte* sysex = 0, size_t ssize = 0); diff --git a/libs/surfaces/generic_midi/midiinvokable.cc b/libs/surfaces/generic_midi/midiinvokable.cc index 79835835a4..42c74553d8 100644 --- a/libs/surfaces/generic_midi/midiinvokable.cc +++ b/libs/surfaces/generic_midi/midiinvokable.cc @@ -25,8 +25,8 @@ using namespace MIDI; -MIDIInvokable::MIDIInvokable (MIDI::Port& p) - : _port (p) +MIDIInvokable::MIDIInvokable (MIDI::Parser& p) + : _parser (p) { data_size = 0; data = 0; @@ -127,12 +127,6 @@ MIDIInvokable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) control_channel = chn; control_additional = additional; - if (_port.parser() == 0) { - return; - } - - Parser& p = *_port.parser(); - int chn_i = chn; /* incoming MIDI is parsed by Ardour' MidiUI event loop/thread, and we want our handlers to execute in that context, so we use @@ -141,27 +135,27 @@ MIDIInvokable::bind_midi (channel_t chn, eventType ev, MIDI::byte additional) switch (ev) { case MIDI::off: - p.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_off, this, _1, _2)); + _parser.channel_note_off[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_off, this, _1, _2)); break; case MIDI::on: - p.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_on, this, _1, _2)); + _parser.channel_note_on[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_note_on, this, _1, _2)); break; case MIDI::controller: - p.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_controller, this, _1, _2)); + _parser.channel_controller[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_controller, this, _1, _2)); break; case MIDI::program: - p.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_program_change, this, _1, _2)); + _parser.channel_program_change[chn_i].connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_program_change, this, _1, _2)); break; case MIDI::sysex: - p.sysex.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_sysex, this, _1, _2, _3)); + _parser.sysex.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_sysex, this, _1, _2, _3)); break; case MIDI::any: - p.any.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_any, this, _1, _2, _3)); + _parser.any.connect_same_thread (midi_sense_connection[0], boost::bind (&MIDIInvokable::midi_sense_any, this, _1, _2, _3)); break; default: diff --git a/libs/surfaces/generic_midi/midiinvokable.h b/libs/surfaces/generic_midi/midiinvokable.h index 62cbab238c..f374a126a5 100644 --- a/libs/surfaces/generic_midi/midiinvokable.h +++ b/libs/surfaces/generic_midi/midiinvokable.h @@ -31,7 +31,6 @@ namespace MIDI { class Channel; - class Port; class Parser; } @@ -40,12 +39,12 @@ class GenericMidiControlProtocol; class MIDIInvokable : public PBD::Stateful { public: - MIDIInvokable (MIDI::Port&); + MIDIInvokable (MIDI::Parser&); virtual ~MIDIInvokable (); virtual int init (GenericMidiControlProtocol&, const std::string&, MIDI::byte* data = 0, size_t dsize = 0); - MIDI::Port& get_port() const { return _port; } + MIDI::Parser& get_parser() { return _parser; } void bind_midi (MIDI::channel_t, MIDI::eventType, MIDI::byte); MIDI::channel_t get_control_channel () { return control_channel; } @@ -55,7 +54,7 @@ class MIDIInvokable : public PBD::Stateful protected: GenericMidiControlProtocol* _ui; std::string _invokable_name; - MIDI::Port& _port; + MIDI::Parser& _parser; PBD::ScopedConnection midi_sense_connection[2]; MIDI::eventType control_type; MIDI::byte control_additional; diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc index 0c45a29378..23cef9d13c 100644 --- a/libs/surfaces/mackie/surface.cc +++ b/libs/surfaces/mackie/surface.cc @@ -24,7 +24,6 @@ #include #include "midi++/port.h" -#include "midi++/manager.h" #include "ardour/automation_control.h" #include "ardour/debug.h" diff --git a/libs/surfaces/mackie/surface_port.cc b/libs/surfaces/mackie/surface_port.cc index 44db30ab1b..fd9feaff74 100644 --- a/libs/surfaces/mackie/surface_port.cc +++ b/libs/surfaces/mackie/surface_port.cc @@ -24,27 +24,27 @@ #include #include "midi++/types.h" -#include "midi++/port.h" -#include "midi++/jack_midi_port.h" #include "midi++/ipmidi_port.h" -#include "midi++/manager.h" +#include "ardour/async_midi_port.h" #include "ardour/debug.h" #include "ardour/rc_configuration.h" #include "ardour/session.h" #include "ardour/audioengine.h" +#include "ardour/async_midi_port.h" +#include "ardour/midiport_manager.h" #include "controls.h" #include "mackie_control_protocol.h" #include "surface.h" #include "surface_port.h" - #include "i18n.h" using namespace std; using namespace Mackie; using namespace PBD; +using namespace ARDOUR; /** @param input_port Input MIDI::Port; this object takes responsibility for * adding & removing it from the MIDI::Manager and destroying it. @param @@ -52,31 +52,16 @@ using namespace PBD; */ SurfacePort::SurfacePort (Surface& s) : _surface (&s) - , _input_port (0) - , _output_port (0) { if (_surface->mcp().device_info().uses_ipmidi()) { _input_port = new MIDI::IPMIDIPort (_surface->mcp().ipmidi_base() +_surface->number()); _output_port = _input_port; } else { - ARDOUR::PortEngine& port_engine (ARDOUR::AudioEngine::instance()->port_engine()); - - _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 - * port. This stops the Generic MIDI UI event loop in ardour from - * attempting to handle these ports. - */ - - _input_port->set_centrally_parsed (false); - _output_port->set_centrally_parsed (false); - - MIDI::Manager * mm = MIDI::Manager::instance(); - - mm->add_port (_input_port); - mm->add_port (_output_port); + _async_in = AudioEngine::instance()->register_input_port (DataType::MIDI, string_compose (_("%1 in"), _surface->name()), true); + _async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, string_compose (_("%1 out"), _surface->name()), true); + + _input_port = boost::dynamic_pointer_cast(_async_in).get(); + _output_port = boost::dynamic_pointer_cast(_async_out).get(); } } @@ -86,17 +71,15 @@ SurfacePort::~SurfacePort() delete _input_port; } else { - MIDI::Manager* mm = MIDI::Manager::instance (); - - if (_input_port) { - mm->remove_port (_input_port); - delete _input_port; + if (_async_in) { + AudioEngine::instance()->unregister_port (_async_in); + _async_in.reset (); } - if (_output_port) { + if (_async_out) { _output_port->drain (10000); - mm->remove_port (_output_port); - delete _output_port; + AudioEngine::instance()->unregister_port (_async_out); + _async_out.reset (); } } } diff --git a/libs/surfaces/mackie/surface_port.h b/libs/surfaces/mackie/surface_port.h index 7dc20a06f2..751ee848d7 100644 --- a/libs/surfaces/mackie/surface_port.h +++ b/libs/surfaces/mackie/surface_port.h @@ -21,16 +21,23 @@ #include #include "pbd/signals.h" + + #include "midi_byte_array.h" #include "types.h" namespace MIDI { - class Port; class Parser; + class Port; } class MackieControlProtocol; +namespace ARDOUR { + class AsyncMIDIPort; + class Port; +} + namespace Mackie { @@ -49,17 +56,17 @@ public: /// an easier way to output bytes via midi int write (const MidiByteArray&); - MIDI::Port& input_port() { return *_input_port; } - const MIDI::Port& input_port() const { return *_input_port; } - MIDI::Port& output_port() { return *_output_port; } - const MIDI::Port& output_port() const { return *_output_port; } + MIDI::Port& input_port() const { return *_input_port; } + MIDI::Port& output_port() const { return *_output_port; } protected: private: - Mackie::Surface* _surface; - MIDI::Port* _input_port; - MIDI::Port* _output_port; + Mackie::Surface* _surface; + MIDI::Port* _input_port; + MIDI::Port* _output_port; + boost::shared_ptr _async_in; + boost::shared_ptr _async_out; }; std::ostream& operator << (std::ostream& , const SurfacePort& port); -- cgit v1.2.3 From 1c49138e0099db37931b34fad552b43c332e187d Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Thu, 5 Sep 2013 13:22:34 -0400 Subject: move MidiPortManager from AudioEngine to Session This makes the responsibilities and ownership of non-Route related MIDI ports more clear, and removes a few wierd bits of code. It also ensures that open/close/open on the same session will retain connections for those MIDI ports --- gtk2_ardour/port_group.cc | 17 +++--- libs/ardour/ardour/audioengine.h | 6 --- libs/ardour/ardour/midiport_manager.h | 2 +- libs/ardour/ardour/port_manager.h | 2 +- libs/ardour/ardour/rc_configuration.h | 6 --- libs/ardour/ardour/session.h | 18 +++++++ libs/ardour/audioengine.cc | 19 ------- libs/ardour/midi_ui.cc | 2 +- libs/ardour/midiport_manager.cc | 10 ++-- libs/ardour/rc_configuration.cc | 17 ------ libs/ardour/session.cc | 13 +++-- libs/ardour/session_export.cc | 6 +-- libs/ardour/session_midi.cc | 46 +++++++++++++++- libs/ardour/session_state.cc | 62 +++++++++++++--------- libs/ardour/session_transport.cc | 10 ++-- libs/ardour/ticker.cc | 2 +- .../generic_midi/generic_midi_control_protocol.cc | 4 +- 17 files changed, 134 insertions(+), 108 deletions(-) (limited to 'libs/ardour/session_export.cc') diff --git a/gtk2_ardour/port_group.cc b/gtk2_ardour/port_group.cc index 67bc40f664..2a93cf6bee 100644 --- a/gtk2_ardour/port_group.cc +++ b/gtk2_ardour/port_group.cc @@ -457,33 +457,32 @@ PortGroupList::gather (ARDOUR::Session* session, ARDOUR::DataType type, bool inp if ((type == DataType::MIDI || type == DataType::NIL)) { boost::shared_ptr sync (new Bundle (_("Sync"), inputs)); AudioEngine* ae = AudioEngine::instance(); - MIDI::MachineControl& mmc (ae->mmc()); if (inputs) { sync->add_channel ( - _("MTC in"), DataType::MIDI, ae->make_port_name_non_relative (ae->mtc_input_port()->name()) + _("MTC in"), DataType::MIDI, ae->make_port_name_non_relative (session->mtc_input_port()->name()) ); sync->add_channel ( - _("MIDI control in"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_input_port()->name()) + _("MIDI control in"), DataType::MIDI, ae->make_port_name_non_relative (session->midi_input_port()->name()) ); sync->add_channel ( - _("MIDI clock in"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_clock_input_port()->name()) + _("MIDI clock in"), DataType::MIDI, ae->make_port_name_non_relative (session->midi_clock_input_port()->name()) ); sync->add_channel ( - _("MMC in"), DataType::MIDI, ae->make_port_name_non_relative (mmc.input_port()->name()) + _("MMC in"), DataType::MIDI, ae->make_port_name_non_relative (session->mmc_input_port()->name()) ); } else { sync->add_channel ( - _("MTC out"), DataType::MIDI, ae->make_port_name_non_relative (ae->mtc_output_port()->name()) + _("MTC out"), DataType::MIDI, ae->make_port_name_non_relative (session->mtc_output_port()->name()) ); sync->add_channel ( - _("MIDI control out"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_output_port()->name()) + _("MIDI control out"), DataType::MIDI, ae->make_port_name_non_relative (session->midi_output_port()->name()) ); sync->add_channel ( - _("MIDI clock out"), DataType::MIDI, ae->make_port_name_non_relative (ae->midi_clock_output_port()->name()) + _("MIDI clock out"), DataType::MIDI, ae->make_port_name_non_relative (session->midi_clock_output_port()->name()) ); sync->add_channel ( - _("MMC out"), DataType::MIDI, ae->make_port_name_non_relative (mmc.output_port()->name()) + _("MMC out"), DataType::MIDI, ae->make_port_name_non_relative (session->mmc_output_port()->name()) ); } diff --git a/libs/ardour/ardour/audioengine.h b/libs/ardour/ardour/audioengine.h index 61fe27abd5..4db1604345 100644 --- a/libs/ardour/ardour/audioengine.h +++ b/libs/ardour/ardour/audioengine.h @@ -36,8 +36,6 @@ #include "pbd/signals.h" #include "pbd/stacktrace.h" -#include "midi++/mmc.h" - #include "ardour/ardour.h" #include "ardour/data_type.h" #include "ardour/session_handle.h" @@ -184,8 +182,6 @@ public: /* sets up the process callback thread */ static void thread_init_callback (void *); - MIDI::MachineControl& mmc() { return _mmc; } - private: AudioEngine (); @@ -207,10 +203,8 @@ public: framecnt_t last_monitor_check; /// the number of frames processed since start() was called framecnt_t _processed_frames; - bool _pre_freewheel_mmc_enabled; Glib::Threads::Thread* m_meter_thread; ProcessThread* _main_thread; - MIDI::MachineControl _mmc; void meter_thread (); void start_metering_thread (); diff --git a/libs/ardour/ardour/midiport_manager.h b/libs/ardour/ardour/midiport_manager.h index 9a32bfe475..9f93c43d5a 100644 --- a/libs/ardour/ardour/midiport_manager.h +++ b/libs/ardour/ardour/midiport_manager.h @@ -65,7 +65,7 @@ class MidiPortManager { boost::shared_ptr midi_clock_input_port() const { return _midi_clock_input_port; } boost::shared_ptr midi_clock_output_port() const { return _midi_clock_output_port; } - void set_midi_port_states (); + void set_midi_port_states (const XMLNodeList&); std::list get_midi_port_states () const; PBD::Signal0 PortsChanged; diff --git a/libs/ardour/ardour/port_manager.h b/libs/ardour/ardour/port_manager.h index 895294810e..6d45597a41 100644 --- a/libs/ardour/ardour/port_manager.h +++ b/libs/ardour/ardour/port_manager.h @@ -38,7 +38,7 @@ namespace ARDOUR { -class PortManager : public MidiPortManager +class PortManager { public: typedef std::map > Ports; diff --git a/libs/ardour/ardour/rc_configuration.h b/libs/ardour/ardour/rc_configuration.h index ff1c5f035c..e2f68477a1 100644 --- a/libs/ardour/ardour/rc_configuration.h +++ b/libs/ardour/ardour/rc_configuration.h @@ -52,7 +52,6 @@ class RCConfiguration : public Configuration XMLNode * instant_xml (const std::string& str); XMLNode* control_protocol_state () { return _control_protocol_state; } - std::list midi_port_states () { return _midi_port_states; } /* define accessor methods */ @@ -81,11 +80,6 @@ class RCConfiguration : public Configuration #undef CONFIG_VARIABLE_SPECIAL XMLNode* _control_protocol_state; - - /** MIDI port nodes from the RC configuration. We store them so that we can set their - state once the audio engine and hence ports are up. - */ - std::list _midi_port_states; }; /* XXX: rename this */ diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 31f0658931..ded5a07f91 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -110,6 +110,8 @@ class IOProcessor; class ImportStatus; class MidiClockTicker; class MidiControlUI; +class MidiPortManager; +class MidiPort; class MidiRegion; class MidiSource; class MidiTrack; @@ -860,6 +862,18 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi boost::shared_ptr ltc_input_io() { return _ltc_input; } boost::shared_ptr ltc_output_io() { return _ltc_output; } + MIDI::Port* midi_input_port () const; + MIDI::Port* midi_output_port () const; + MIDI::Port* mmc_output_port () const; + MIDI::Port* mmc_input_port () const; + + boost::shared_ptr midi_clock_output_port () const; + boost::shared_ptr midi_clock_input_port () const; + boost::shared_ptr mtc_output_port () const; + boost::shared_ptr mtc_input_port () const; + + MIDI::MachineControl& mmc() { return *_mmc; } + /* Callbacks specifically related to JACK, and called directly * from the JACK audio backend. */ @@ -1597,6 +1611,10 @@ class Session : public PBD::StatefulDestructible, public PBD::ScopedConnectionLi void reconnect_ltc_input (); void reconnect_ltc_output (); + + /* persistent, non-track related MIDI ports */ + MidiPortManager* _midi_ports; + MIDI::MachineControl* _mmc; }; } // namespace ARDOUR diff --git a/libs/ardour/audioengine.cc b/libs/ardour/audioengine.cc index 109f76334a..5b19253a26 100644 --- a/libs/ardour/audioengine.cc +++ b/libs/ardour/audioengine.cc @@ -71,7 +71,6 @@ AudioEngine::AudioEngine () , monitor_check_interval (INT32_MAX) , last_monitor_check (0) , _processed_frames (0) - , _pre_freewheel_mmc_enabled (false) , m_meter_thread (0) , _main_thread (0) { @@ -543,12 +542,6 @@ AudioEngine::start () return 0; } - /* if we're still connected (i.e. previously paused), no need to - * re-register ports. - */ - - bool have_ports = (!ports.reader()->empty()); - _processed_frames = 0; last_monitor_check = 0; @@ -566,11 +559,6 @@ AudioEngine::start () } } - if (!have_ports) { - PortManager::create_ports (); - _mmc.set_ports (mmc_input_port(), mmc_output_port()); - } - start_metering_thread (); Running(); /* EMIT SIGNAL */ @@ -903,13 +891,6 @@ AudioEngine::sync_callback (TransportState state, framepos_t position) void AudioEngine::freewheel_callback (bool onoff) { - if (onoff) { - _pre_freewheel_mmc_enabled = _mmc.send_enabled (); - _mmc.enable_send (false); - } else { - _mmc.enable_send (_pre_freewheel_mmc_enabled); - } - _freewheeling = onoff; } diff --git a/libs/ardour/midi_ui.cc b/libs/ardour/midi_ui.cc index e75c05c593..7346c0244c 100644 --- a/libs/ardour/midi_ui.cc +++ b/libs/ardour/midi_ui.cc @@ -118,7 +118,7 @@ void MidiControlUI::reset_ports () { if (port_sources.empty()) { - AsyncMIDIPort* async = dynamic_cast (AudioEngine::instance()->midi_input_port()); + AsyncMIDIPort* async = dynamic_cast (_session.midi_input_port()); if (!async) { return; diff --git a/libs/ardour/midiport_manager.cc b/libs/ardour/midiport_manager.cc index 7abd47580b..d17401cee8 100644 --- a/libs/ardour/midiport_manager.cc +++ b/libs/ardour/midiport_manager.cc @@ -32,6 +32,7 @@ using namespace PBD; MidiPortManager::MidiPortManager () { + create_ports (); } MidiPortManager::~MidiPortManager () @@ -110,21 +111,16 @@ MidiPortManager::create_ports () _mtc_output_port->set_always_parse (true); _midi_clock_input_port->set_always_parse (true); _midi_clock_output_port->set_always_parse (true); - - set_midi_port_states (); } void -MidiPortManager::set_midi_port_states () +MidiPortManager::set_midi_port_states (const XMLNodeList&nodes) { - list nodes; XMLProperty* prop; typedef map > PortMap; PortMap ports; const int version = 0; - nodes = Config->midi_port_states (); - ports.insert (make_pair (_mtc_input_port->name(), _mtc_input_port)); ports.insert (make_pair (_mtc_output_port->name(), _mtc_output_port)); ports.insert (make_pair (_midi_clock_input_port->name(), _midi_clock_input_port)); @@ -134,7 +130,7 @@ MidiPortManager::set_midi_port_states () ports.insert (make_pair (_mmc_input_port->name(), _mmc_in)); ports.insert (make_pair (_mmc_output_port->name(), _mmc_out)); - for (list::iterator n = nodes.begin(); n != nodes.end(); ++n) { + for (XMLNodeList::const_iterator n = nodes.begin(); n != nodes.end(); ++n) { if ((prop = (*n)->property (X_("name"))) == 0) { continue; } diff --git a/libs/ardour/rc_configuration.cc b/libs/ardour/rc_configuration.cc index 071d50ac03..f4612699d4 100644 --- a/libs/ardour/rc_configuration.cc +++ b/libs/ardour/rc_configuration.cc @@ -65,10 +65,6 @@ RCConfiguration::RCConfiguration () RCConfiguration::~RCConfiguration () { - for (list::iterator i = _midi_port_states.begin(); i != _midi_port_states.end(); ++i) { - delete *i; - } - delete _control_protocol_state; } @@ -176,11 +172,6 @@ RCConfiguration::get_state () root = new XMLNode("Ardour"); - list midi_port_nodes = AudioEngine::instance()->get_midi_port_states(); - for (list::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) { - root->add_child_nocopy (**n); - } - root->add_child_nocopy (get_variables ()); root->add_child_nocopy (SessionMetadata::Metadata()->get_user_state()); @@ -226,12 +217,6 @@ RCConfiguration::set_state (const XMLNode& root, int version) XMLNodeConstIterator niter; XMLNode *node; - for (list::iterator i = _midi_port_states.begin(); i != _midi_port_states.end(); ++i) { - delete *i; - } - - _midi_port_states.clear (); - Stateful::save_extra_xml (root); for (niter = nlist.begin(); niter != nlist.end(); ++niter) { @@ -244,8 +229,6 @@ RCConfiguration::set_state (const XMLNode& root, int version) SessionMetadata::Metadata()->set_state (*node, version); } else if (node->name() == ControlProtocolManager::state_node_name) { _control_protocol_state = new XMLNode (*node); - } else if (node->name() == ARDOUR::Port::state_node_name) { - _midi_port_states.push_back (new XMLNode (*node)); } } diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index dc6456b73f..4dc5a07a77 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -157,6 +157,11 @@ Session::Session (AudioEngine &eng, _locations = new Locations (*this); ltc_encoder = NULL; + _midi_ports = new MidiPortManager; + _mmc = new MIDI::MachineControl; + + _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port()); + if (how_many_dsp_threads () > 1) { /* For now, only create the graph if we are using >1 DSP threads, as it is a bit slower than the old code with 1 thread. @@ -330,6 +335,8 @@ Session::destroy () /* not strictly necessary, but doing it here allows the shared_ptr debugging to work */ playlists.reset (); + delete _mmc; + delete _midi_ports; delete _locations; DEBUG_TRACE (DEBUG::Destruction, "Session::destroy() done\n"); @@ -1175,7 +1182,7 @@ Session::enable_record () if (g_atomic_int_compare_and_exchange (&_record_status, rs, Recording)) { _last_record_location = _transport_frame; - AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordStrobe)); + _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordStrobe)); if (Config->get_monitoring_model() == HardwareMonitoring && config.get_auto_input()) { set_track_monitor_input_status (true); @@ -1196,7 +1203,7 @@ Session::disable_record (bool rt_context, bool force) if ((!Config->get_latched_record_enable () && !play_loop) || force) { g_atomic_int_set (&_record_status, Disabled); - AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit)); + _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordExit)); } else { if (rs == Recording) { g_atomic_int_set (&_record_status, Enabled); @@ -1250,7 +1257,7 @@ Session::maybe_enable_record () enable_record (); } } else { - AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordPause)); + _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdRecordPause)); RecordStateChanged (); /* EMIT SIGNAL */ } diff --git a/libs/ardour/session_export.cc b/libs/ardour/session_export.cc index ab37e915bf..62eb61ab83 100644 --- a/libs/ardour/session_export.cc +++ b/libs/ardour/session_export.cc @@ -92,8 +92,8 @@ Session::pre_export () /* disable MMC output early */ - _pre_export_mmc_enabled = AudioEngine::instance()->mmc().send_enabled (); - AudioEngine::instance()->mmc().enable_send (false); + _pre_export_mmc_enabled = _mmc->send_enabled (); + _mmc->enable_send (false); return 0; } @@ -236,7 +236,7 @@ Session::finalize_audio_export () export_freewheel_connection.disconnect(); - AudioEngine::instance()->mmc().enable_send (_pre_export_mmc_enabled); + _mmc->enable_send (_pre_export_mmc_enabled); /* maybe write CUE/TOC */ diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index 07a34283e3..6d3083df77 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -425,7 +425,7 @@ Session::send_full_time_code (framepos_t const t, pframes_t nframes) // Send message at offset 0, sent time is for the start of this cycle - MidiBuffer& mb (AudioEngine::instance()->mtc_output_port()->get_midi_buffer (nframes)); + MidiBuffer& mb (_midi_ports->mtc_output_port()->get_midi_buffer (nframes)); mb.push_back (0, sizeof (msg), msg); _pframes_since_last_mtc = 0; @@ -515,7 +515,7 @@ Session::send_midi_time_code_for_cycle (framepos_t start_frame, framepos_t end_f pframes_t const out_stamp = (msg_time - start_frame) / _transport_speed; assert (out_stamp < nframes); - MidiBuffer& mb (AudioEngine::instance()->mtc_output_port()->get_midi_buffer(nframes)); + MidiBuffer& mb (_midi_ports->mtc_output_port()->get_midi_buffer(nframes)); if (!mb.push_back (out_stamp, 2, mtc_msg)) { error << string_compose(_("Session: cannot send quarter-frame MTC message (%1)"), strerror (errno)) << endmsg; @@ -603,3 +603,45 @@ Session::start_midi_thread () return 0; } +MIDI::Port* +Session::midi_input_port () const +{ + return _midi_ports->midi_input_port (); +} +MIDI::Port* +Session::midi_output_port () const +{ + return _midi_ports->midi_output_port (); +} +boost::shared_ptr +Session::midi_clock_output_port () const +{ + return _midi_ports->midi_clock_output_port (); +} +boost::shared_ptr +Session::midi_clock_input_port () const +{ + return _midi_ports->midi_clock_input_port (); +} +boost::shared_ptr +Session::mtc_output_port () const +{ + return _midi_ports->mtc_output_port (); +} +boost::shared_ptr +Session::mtc_input_port () const +{ + return _midi_ports->mtc_input_port (); +} + +MIDI::Port* +Session::mmc_output_port () const +{ + return _midi_ports->mmc_output_port (); +} + +MIDI::Port* +Session::mmc_input_port () const +{ + return _midi_ports->mmc_input_port (); +} diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 50905ef434..a7d7a0be4c 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -361,8 +361,8 @@ Session::second_stage_init () // send_full_time_code (0); _engine.transport_locate (0); - AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset)); - AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (Timecode::Time ())); + _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset)); + _mmc->send (MIDI::MachineControlCommand (Timecode::Time ())); MIDI::Name::MidiPatchManager::instance().set_session (this); @@ -983,6 +983,15 @@ Session::state (bool full_state) /* various options */ + list midi_port_nodes = _midi_ports->get_midi_port_states(); + if (!midi_port_nodes.empty()) { + XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts"); + for (list::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) { + midi_port_stuff->add_child_nocopy (**n); + } + node->add_child_nocopy (*midi_port_stuff); + } + node->add_child_nocopy (config.get_variables ()); node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state()); @@ -1188,6 +1197,11 @@ Session::set_state (const XMLNode& node, int version) Evoral::init_event_id_counter (atoi (prop->value())); } + + if ((child = find_named_node (node, "MIDIPorts")) != 0) { + _midi_ports->set_midi_port_states (child->children()); + } + IO::disable_connecting (); Stateful::save_extra_xml (node); @@ -3364,11 +3378,11 @@ Session::config_changed (std::string p, bool ours) } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") { - AudioEngine::instance()->mmc().set_receive_device_id (Config->get_mmc_receive_device_id()); + _mmc->set_receive_device_id (Config->get_mmc_receive_device_id()); } else if (p == "mmc-send-id" || p == "mmc-send-device-id") { - AudioEngine::instance()->mmc().set_send_device_id (Config->get_mmc_send_device_id()); + _mmc->set_send_device_id (Config->get_mmc_send_device_id()); } else if (p == "midi-control") { @@ -3431,7 +3445,7 @@ Session::config_changed (std::string p, bool ours) } else if (p == "send-mmc") { - AudioEngine::instance()->mmc().enable_send (Config->get_send_mmc ()); + _mmc->enable_send (Config->get_send_mmc ()); } else if (p == "midi-feedback") { @@ -3489,13 +3503,13 @@ Session::config_changed (std::string p, bool ours) } else if (p == "initial-program-change") { - if (AudioEngine::instance()->mmc().output_port() && Config->get_initial_program_change() >= 0) { + if (_mmc->output_port() && Config->get_initial_program_change() >= 0) { MIDI::byte buf[2]; buf[0] = MIDI::program; // channel zero by default buf[1] = (Config->get_initial_program_change() & 0x7f); - AudioEngine::instance()->mmc().output_port()->midimsg (buf, sizeof (buf), 0); + _mmc->output_port()->midimsg (buf, sizeof (buf), 0); } } else if (p == "solo-mute-override") { // catch_up_on_solo_mute_override (); @@ -3559,27 +3573,25 @@ Session::load_diskstreams_2X (XMLNode const & node, int) void Session::setup_midi_machine_control () { - MIDI::MachineControl& mmc (AudioEngine::instance()->mmc ()); - - mmc.Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); - mmc.DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); - mmc.Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1)); - mmc.FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1)); - mmc.Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1)); - mmc.Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1)); - mmc.RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1)); - mmc.RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1)); - mmc.RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1)); - mmc.Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2)); - mmc.Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2)); - mmc.Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3)); - mmc.TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3)); + _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); + _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1)); + _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1)); + _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1)); + _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1)); + _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1)); + _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1)); + _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1)); + _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1)); + _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2)); + _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2)); + _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3)); + _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3)); /* also handle MIDI SPP because its so common */ - mmc.SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this)); - mmc.SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this)); - mmc.SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this)); + _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this)); + _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this)); + _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this)); } boost::shared_ptr diff --git a/libs/ardour/session_transport.cc b/libs/ardour/session_transport.cc index 1e492741b8..ab6d68fd67 100644 --- a/libs/ardour/session_transport.cc +++ b/libs/ardour/session_transport.cc @@ -618,7 +618,7 @@ Session::non_realtime_stop (bool abort, int on_entry, bool& finished) _send_timecode_update = true; if (!dynamic_cast(_slave)) { - AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop)); + _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdStop)); /* This (::non_realtime_stop()) gets called by main process thread, which will lead to confusion @@ -1271,7 +1271,7 @@ Session::start_transport () Timecode::Time time; timecode_time_subframes (_transport_frame, time); if (!dynamic_cast(_slave)) { - AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay)); + _mmc->send (MIDI::MachineControlCommand (MIDI::MachineControl::cmdDeferredPlay)); } } @@ -1392,7 +1392,7 @@ Session::switch_to_sync_source (SyncSource src) } try { - new_slave = new MTC_Slave (*this, *AudioEngine::instance()->mtc_input_port()); + new_slave = new MTC_Slave (*this, *_midi_ports->mtc_input_port()); } catch (failed_constructor& err) { @@ -1421,7 +1421,7 @@ Session::switch_to_sync_source (SyncSource src) } try { - new_slave = new MIDIClock_Slave (*this, *AudioEngine::instance()->midi_clock_input_port(), 24); + new_slave = new MIDIClock_Slave (*this, *_midi_ports->midi_clock_input_port(), 24); } catch (failed_constructor& err) { @@ -1648,7 +1648,7 @@ Session::send_mmc_locate (framepos_t t) if (!_engine.freewheeling()) { Timecode::Time time; timecode_time_subframes (t, time); - AudioEngine::instance()->mmc().send (MIDI::MachineControlCommand (time)); + _mmc->send (MIDI::MachineControlCommand (time)); } } diff --git a/libs/ardour/ticker.cc b/libs/ardour/ticker.cc index 0ed4427b72..9a29df2641 100644 --- a/libs/ardour/ticker.cc +++ b/libs/ardour/ticker.cc @@ -150,7 +150,7 @@ MidiClockTicker::session_going_away () void MidiClockTicker::update_midi_clock_port() { - _midi_port = AudioEngine::instance()->midi_clock_output_port(); + _midi_port = _session->midi_clock_output_port(); } void diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index 2820b069dc..ba1858a174 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -60,8 +60,8 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) , _threshold (10) , gui (0) { - _input_port = AudioEngine::instance()->midi_input_port (); - _output_port = AudioEngine::instance()->midi_output_port (); + _input_port = s.midi_input_port (); + _output_port = s.midi_output_port (); do_feedback = false; _feedback_interval = 10000; // microseconds -- cgit v1.2.3