From 9ac6bb9befa047a6c349bed02d40da84600b67cc Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 24 Jul 2013 19:29:45 -0400 Subject: part-way through getting the audioengine changes to compile --- libs/midi++2/jack_midi_port.cc | 123 +++++++++++++++++------------------ libs/midi++2/manager.cc | 24 +++---- libs/midi++2/midi++/jack_midi_port.h | 21 +++--- libs/midi++2/midi++/manager.h | 10 ++- libs/midi++2/midi++/mmc.h | 8 ++- libs/midi++2/mmc.cc | 8 ++- libs/midi++2/wscript | 3 +- 7 files changed, 103 insertions(+), 94 deletions(-) (limited to 'libs/midi++2') diff --git a/libs/midi++2/jack_midi_port.cc b/libs/midi++2/jack_midi_port.cc index 05df3171fa..372a7891c9 100644 --- a/libs/midi++2/jack_midi_port.cc +++ b/libs/midi++2/jack_midi_port.cc @@ -22,9 +22,6 @@ #include #include -#include -#include - #include "pbd/xml++.h" #include "pbd/error.h" #include "pbd/failed_constructor.h" @@ -45,37 +42,34 @@ template class EventRingBuffer; } pthread_t JackMIDIPort::_process_thread; -Signal0 JackMIDIPort::JackHalted; +Signal0 JackMIDIPort::EngineHalted; Signal0 JackMIDIPort::MakeConnections; -JackMIDIPort::JackMIDIPort (string const & name, Flags flags, jack_client_t* jack_client) +JackMIDIPort::JackMIDIPort (string const & name, Flags flags, ARDOUR::PortEngine& pengine) : Port (name, flags) + , _port_engine (pengine) + , _port_handle (0) , _currently_in_cycle (false) , _nframes_this_cycle (0) - , _jack_client (jack_client) - , _jack_port (0) , _last_write_timestamp (0) , output_fifo (512) , input_fifo (1024) , xthread (true) { - assert (jack_client); init (name, flags); } -JackMIDIPort::JackMIDIPort (const XMLNode& node, jack_client_t* jack_client) +JackMIDIPort::JackMIDIPort (const XMLNode& node, ARDOUR::PortEngine& pengine) : Port (node) + , _port_engine (pengine) + , _port_handle (0) , _currently_in_cycle (false) , _nframes_this_cycle (0) - , _jack_client (jack_client) - , _jack_port (0) , _last_write_timestamp (0) , output_fifo (512) , input_fifo (1024) , xthread (true) { - assert (jack_client); - Descriptor desc (node); init (desc.tag, desc.flags); set_state (node); @@ -89,17 +83,15 @@ JackMIDIPort::init (const string& /*name*/, Flags /*flags*/) } MakeConnections.connect_same_thread (connect_connection, boost::bind (&JackMIDIPort::make_connections, this)); - JackHalted.connect_same_thread (halt_connection, boost::bind (&JackMIDIPort::jack_halted, this)); + EngineHalted.connect_same_thread (halt_connection, boost::bind (&JackMIDIPort::engine_halted, this)); } JackMIDIPort::~JackMIDIPort () { - if (_jack_port) { - if (_jack_client) { - jack_port_unregister (_jack_client, _jack_port); - _jack_port = 0; - } + if (_port_handle) { + _port_engine.unregister_port (_port_handle); + _port_handle = 0; } } @@ -143,7 +135,7 @@ JackMIDIPort::parse (framecnt_t timestamp) void JackMIDIPort::cycle_start (pframes_t nframes) { - assert (_jack_port); + assert (_port_handle); _currently_in_cycle = true; _nframes_this_cycle = nframes; @@ -151,21 +143,23 @@ JackMIDIPort::cycle_start (pframes_t nframes) assert(_nframes_this_cycle == nframes); if (sends_output()) { - void *buffer = jack_port_get_buffer (_jack_port, nframes); + void *buffer = _port_engine.get_buffer (_port_handle, nframes); jack_midi_clear_buffer (buffer); flush (buffer); } if (receives_input()) { - void* jack_buffer = jack_port_get_buffer(_jack_port, nframes); - const pframes_t event_count = jack_midi_get_event_count(jack_buffer); + void* buffer = _port_engine.get_buffer (_port_handle, nframes); + const pframes_t event_count = _port_engine.get_midi_event_count (buffer); - jack_midi_event_t ev; - timestamp_t cycle_start_frame = jack_last_frame_time (_jack_client); + pframes_t time; + size_t size; + uint8_t* buf; + timestamp_t cycle_start_frame = _port_engine.last_frame_time (); for (pframes_t i = 0; i < event_count; ++i) { - jack_midi_event_get (&ev, jack_buffer, i); - input_fifo.write (cycle_start_frame + ev.time, (Evoral::EventType) 0, ev.size, ev.buffer); + _port_engine.midi_event_get (time, size, &buf, buffer, i); + input_fifo.write (cycle_start_frame + time, (Evoral::EventType) 0, size, buf); } if (event_count) { @@ -178,7 +172,7 @@ void JackMIDIPort::cycle_end () { if (sends_output()) { - flush (jack_port_get_buffer (_jack_port, _nframes_this_cycle)); + flush (_port_engine.get_buffer (_port_handle, _nframes_this_cycle)); } _currently_in_cycle = false; @@ -186,10 +180,9 @@ JackMIDIPort::cycle_end () } void -JackMIDIPort::jack_halted () +JackMIDIPort::engine_halted () { - _jack_client = 0; - _jack_port = 0; + _port_handle = 0; } void @@ -216,7 +209,7 @@ JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp) { int ret = 0; - if (!_jack_client || !_jack_port) { + if (!_port_handle) { /* poof ! make it just vanish into thin air, since we are no longer connected to JACK. */ @@ -268,18 +261,18 @@ JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp) if (timestamp == 0) { timestamp = _last_write_timestamp; } - - if ((ret = jack_midi_event_write (jack_port_get_buffer (_jack_port, _nframes_this_cycle), - timestamp, msg, msglen)) == 0) { + + if ((ret = _port_engine.midi_event_put (_port_engine.get_buffer (_port_handle, _nframes_this_cycle), + timestamp, msg, msglen)) == 0) { ret = msglen; _last_write_timestamp = timestamp; } else { cerr << "write of " << msglen << " @ " << timestamp << " failed, port holds " - << jack_midi_get_event_count (jack_port_get_buffer (_jack_port, _nframes_this_cycle)) - << " port is " << _jack_port + << _port_engine.get_midi_event_count (_port_engine.get_buffer (_port_handle, _nframes_this_cycle)) + << " port is " << _port_handle << " ntf = " << _nframes_this_cycle - << " buf = " << jack_port_get_buffer (_jack_port, _nframes_this_cycle) + << " buf = " << _port_engine.get_buffer (_port_handle, _nframes_this_cycle) << " ret = " << ret << endl; PBD::stacktrace (cerr, 20); @@ -305,7 +298,7 @@ JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp) } void -JackMIDIPort::flush (void* jack_port_buffer) +JackMIDIPort::flush (void* port_buffer) { RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0 } }; size_t written; @@ -320,8 +313,7 @@ JackMIDIPort::flush (void* jack_port_buffer) Evoral::Event* evp = vec.buf[0]; for (size_t n = 0; n < vec.len[0]; ++n, ++evp) { - jack_midi_event_write (jack_port_buffer, - (timestamp_t) evp->time(), evp->buffer(), evp->size()); + _port_engine.midi_event_put (port_buffer, (timestamp_t) evp->time(), evp->buffer(), evp->size()); } } @@ -329,8 +321,7 @@ JackMIDIPort::flush (void* jack_port_buffer) Evoral::Event* evp = vec.buf[1]; for (size_t n = 0; n < vec.len[1]; ++n, ++evp) { - jack_midi_event_write (jack_port_buffer, - (timestamp_t) evp->time(), evp->buffer(), evp->size()); + _port_engine.midi_event_put (port_buffer, (timestamp_t) evp->time(), evp->buffer(), evp->size()); } } @@ -364,8 +355,21 @@ JackMIDIPort::read (byte *, size_t) int JackMIDIPort::create_port () { - _jack_port = jack_port_register(_jack_client, _tagname.c_str(), JACK_DEFAULT_MIDI_TYPE, _flags, 0); - return _jack_port == 0 ? -1 : 0; + ARDOUR::PortFlags f = ARDOUR::PortFlags (0); + + /* convert MIDI::Port::Flags to ARDOUR::PortFlags ... sigh */ + + if (_flags & IsInput) { + f = ARDOUR::PortFlags (f | ARDOUR::IsInput); + } + + if (_flags & IsOutput) { + f = ARDOUR::PortFlags (f | ARDOUR::IsOutput); + } + + _port_handle = _port_engine.register_port (_tagname, ARDOUR::DataType::MIDI, f); + + return _port_handle == 0 ? -1 : 0; } XMLNode& @@ -386,18 +390,16 @@ JackMIDIPort::get_state () const write (device_inquiry, sizeof (device_inquiry), 0); #endif - if (_jack_port) { + if (_port_handle) { - const char** jc = jack_port_get_connections (_jack_port); + vector connections; + _port_engine.get_connections (_port_handle, connections); string connection_string; - if (jc) { - for (int i = 0; jc[i]; ++i) { - if (i > 0) { - connection_string += ','; - } - connection_string += jc[i]; + for (vector::iterator i = connections.begin(); i != connections.end(); ++i) { + if (i != connections.begin()) { + connection_string += ','; } - free (jc); + connection_string += *i; } if (!connection_string.empty()) { @@ -435,14 +437,8 @@ JackMIDIPort::make_connections () vector ports; split (_connections, ports, ','); for (vector::iterator x = ports.begin(); x != ports.end(); ++x) { - if (_jack_client) { - if (receives_input()) { - jack_connect (_jack_client, (*x).c_str(), jack_port_name (_jack_port)); - } else { - jack_connect (_jack_client, jack_port_name (_jack_port), (*x).c_str()); - } - /* ignore failures */ - } + _port_engine.connect (_port_handle, *x); + /* ignore failures */ } } @@ -462,9 +458,8 @@ JackMIDIPort::is_process_thread() } void -JackMIDIPort::reestablish (jack_client_t* jack) +JackMIDIPort::reestablish () { - _jack_client = jack; int const r = create_port (); if (r) { diff --git a/libs/midi++2/manager.cc b/libs/midi++2/manager.cc index 822c74e125..3df9681dd3 100644 --- a/libs/midi++2/manager.cc +++ b/libs/midi++2/manager.cc @@ -36,17 +36,17 @@ using namespace PBD; Manager *Manager::theManager = 0; -Manager::Manager (jack_client_t* jack) +Manager::Manager (ARDOUR::PortEngine& eng) : _ports (new PortList) { - _mmc = new MachineControl (this, jack); + _mmc = new MachineControl (this, eng); - _mtc_input_port = add_port (new MIDI::JackMIDIPort ("MTC in", Port::IsInput, jack)); - _mtc_output_port = add_port (new MIDI::JackMIDIPort ("MTC out", Port::IsOutput, jack)); - _midi_input_port = add_port (new MIDI::JackMIDIPort ("MIDI control in", Port::IsInput, jack)); - _midi_output_port = add_port (new MIDI::JackMIDIPort ("MIDI control out", Port::IsOutput, jack)); - _midi_clock_input_port = add_port (new MIDI::JackMIDIPort ("MIDI clock in", Port::IsInput, jack)); - _midi_clock_output_port = add_port (new MIDI::JackMIDIPort ("MIDI clock out", Port::IsOutput, jack)); + _mtc_input_port = add_port (new MIDI::JackMIDIPort ("MTC in", Port::IsInput, eng)); + _mtc_output_port = add_port (new MIDI::JackMIDIPort ("MTC out", Port::IsOutput, eng)); + _midi_input_port = add_port (new MIDI::JackMIDIPort ("MIDI control in", Port::IsInput, eng)); + _midi_output_port = add_port (new MIDI::JackMIDIPort ("MIDI control out", Port::IsOutput, eng)); + _midi_clock_input_port = add_port (new MIDI::JackMIDIPort ("MIDI clock in", Port::IsInput, eng)); + _midi_clock_output_port = add_port (new MIDI::JackMIDIPort ("MIDI clock out", Port::IsOutput, eng)); } Manager::~Manager () @@ -113,14 +113,14 @@ Manager::cycle_end() /** Re-register ports that disappear on JACK shutdown */ void -Manager::reestablish (jack_client_t* jack) +Manager::reestablish () { boost::shared_ptr pr = _ports.reader (); for (PortList::const_iterator p = pr->begin(); p != pr->end(); ++p) { JackMIDIPort* pp = dynamic_cast (*p); if (pp) { - pp->reestablish (jack); + pp->reestablish (); } } } @@ -157,10 +157,10 @@ Manager::port (string const & n) } void -Manager::create (jack_client_t* jack) +Manager::create (ARDOUR::PortEngine& eng) { assert (theManager == 0); - theManager = new Manager (jack); + theManager = new Manager (eng); } void diff --git a/libs/midi++2/midi++/jack_midi_port.h b/libs/midi++2/midi++/jack_midi_port.h index a8859387a4..492756067c 100644 --- a/libs/midi++2/midi++/jack_midi_port.h +++ b/libs/midi++2/midi++/jack_midi_port.h @@ -22,8 +22,6 @@ #include #include -#include - #include "pbd/xml++.h" #include "pbd/crossthread.h" #include "pbd/signals.h" @@ -36,6 +34,8 @@ #include "midi++/parser.h" #include "midi++/port.h" +#include "ardour/port_engine.h" + namespace MIDI { class Channel; @@ -43,8 +43,8 @@ class PortRequest; class JackMIDIPort : public Port { public: - JackMIDIPort (std::string const &, Port::Flags, jack_client_t *); - JackMIDIPort (const XMLNode&, jack_client_t *); + JackMIDIPort (std::string const &, Port::Flags, ARDOUR::PortEngine&); + JackMIDIPort (const XMLNode&, ARDOUR::PortEngine&); ~JackMIDIPort (); XMLNode& get_state () const; @@ -61,7 +61,7 @@ class JackMIDIPort : public Port { pframes_t nframes_this_cycle() const { return _nframes_this_cycle; } - void reestablish (jack_client_t *); + void reestablish (); void reconnect (); static void set_process_thread (pthread_t); @@ -69,13 +69,14 @@ class JackMIDIPort : public Port { static bool is_process_thread(); static PBD::Signal0 MakeConnections; - static PBD::Signal0 JackHalted; + static PBD::Signal0 EngineHalted; private: + ARDOUR::PortEngine& _port_engine; + ARDOUR::PortEngine::PortHandle _port_handle; + bool _currently_in_cycle; pframes_t _nframes_this_cycle; - jack_client_t* _jack_client; - jack_port_t* _jack_port; timestamp_t _last_write_timestamp; RingBuffer< Evoral::Event > output_fifo; Evoral::EventRingBuffer input_fifo; @@ -89,8 +90,8 @@ private: std::string _connections; PBD::ScopedConnection connect_connection; PBD::ScopedConnection halt_connection; - void flush (void* jack_port_buffer); - void jack_halted (); + void flush (void* port_buffer); + void engine_halted (); void make_connections (); void init (std::string const &, Flags); diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h index c37ba392b4..7f4df5c6c8 100644 --- a/libs/midi++2/midi++/manager.h +++ b/libs/midi++2/midi++/manager.h @@ -29,6 +29,10 @@ #include "midi++/types.h" #include "midi++/port.h" +namespace ARDOUR { + class PortEngine; +} + namespace MIDI { class MachineControl; @@ -69,14 +73,14 @@ class Manager { boost::shared_ptr get_midi_ports() const { return _ports.reader (); } - static void create (jack_client_t* jack); + static void create (ARDOUR::PortEngine&); static Manager *instance () { return theManager; } static void destroy (); - void reestablish (jack_client_t *); + void reestablish (); void reconnect (); PBD::Signal0 PortsChanged; @@ -84,7 +88,7 @@ class Manager { private: /* This is a SINGLETON pattern */ - Manager (jack_client_t *); + Manager (ARDOUR::PortEngine&); static Manager *theManager; MIDI::MachineControl* _mmc; diff --git a/libs/midi++2/midi++/mmc.h b/libs/midi++2/midi++/mmc.h index 18204e3fa8..0f362678ce 100644 --- a/libs/midi++2/midi++/mmc.h +++ b/libs/midi++2/midi++/mmc.h @@ -22,11 +22,17 @@ #include #include "timecode/time.h" + #include "pbd/signals.h" #include "pbd/ringbuffer.h" + #include "midi++/types.h" #include "midi++/parser.h" +namespace ARDOUR { + class PortEngine; +} + namespace MIDI { class Port; @@ -89,7 +95,7 @@ class MachineControl cmdResume = 0x7F }; - MachineControl (Manager *, jack_client_t *); + MachineControl (Manager *, ARDOUR::PortEngine&); Port* input_port() { return _input_port; } Port* output_port() { return _output_port; } diff --git a/libs/midi++2/mmc.cc b/libs/midi++2/mmc.cc index 06eadb5b34..0a71463721 100644 --- a/libs/midi++2/mmc.cc +++ b/libs/midi++2/mmc.cc @@ -22,7 +22,9 @@ #include #include "timecode/time.h" + #include "pbd/error.h" + #include "midi++/mmc.h" #include "midi++/port.h" #include "midi++/jack_midi_port.h" @@ -196,15 +198,15 @@ static void build_mmc_cmd_map () } -MachineControl::MachineControl (Manager* m, jack_client_t* jack) +MachineControl::MachineControl (Manager* m, ARDOUR::PortEngine& pengine) { build_mmc_cmd_map (); _receive_device_id = 0x7f; _send_device_id = 0x7f; - _input_port = m->add_port (new JackMIDIPort ("MMC in", Port::IsInput, jack)); - _output_port = m->add_port (new JackMIDIPort ("MMC out", Port::IsOutput, jack)); + _input_port = m->add_port (new JackMIDIPort ("MMC in", Port::IsInput, pengine)); + _output_port = m->add_port (new JackMIDIPort ("MMC out", Port::IsOutput, pengine)); _input_port->parser()->mmc.connect_same_thread (port_connections, boost::bind (&MachineControl::process_mmc_message, this, _1, _2, _3)); _input_port->parser()->start.connect_same_thread (port_connections, boost::bind (&MachineControl::spp_start, this)); diff --git a/libs/midi++2/wscript b/libs/midi++2/wscript index ea8988110d..8a4f2f6c69 100644 --- a/libs/midi++2/wscript +++ b/libs/midi++2/wscript @@ -26,6 +26,7 @@ out = 'build' path_prefix = 'libs/midi++2/' + libmidi_sources = [ 'midi.cc', 'channel.cc', @@ -68,7 +69,7 @@ def build(bld): obj.cxxflags = [ '-fPIC', '-DWITH_JACK_MIDI' ] # everybody loves JACK obj.export_includes = ['.'] - obj.includes = ['.', '../surfaces/control_protocol'] + obj.includes = ['.', '../surfaces/control_protocol', '../ardour' ] obj.name = 'libmidipp' obj.target = 'midipp' obj.uselib = 'GLIBMM SIGCPP XML JACK OSX' -- 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/midi++2') 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 83a0c30c24ce6bb6e3e718c267a82fbaffc33b4b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 7 Aug 2013 22:21:36 -0400 Subject: major redesign of MIDI port heirarchy and management basic, very flaky functionality is back. program unstable at present --- libs/ardour/ardour/midiport_manager.h | 94 +++++++ libs/ardour/midiport_manager.cc | 89 +++++++ libs/midi++2/jack_midi_port.cc | 474 ---------------------------------- libs/midi++2/manager.cc | 183 ------------- libs/midi++2/midi++/jack_midi_port.h | 104 -------- libs/midi++2/midi++/manager.h | 107 -------- 6 files changed, 183 insertions(+), 868 deletions(-) create mode 100644 libs/ardour/ardour/midiport_manager.h create mode 100644 libs/ardour/midiport_manager.cc delete mode 100644 libs/midi++2/jack_midi_port.cc delete mode 100644 libs/midi++2/manager.cc delete mode 100644 libs/midi++2/midi++/jack_midi_port.h delete mode 100644 libs/midi++2/midi++/manager.h (limited to 'libs/midi++2') diff --git a/libs/ardour/ardour/midiport_manager.h b/libs/ardour/ardour/midiport_manager.h new file mode 100644 index 0000000000..9c45e60341 --- /dev/null +++ b/libs/ardour/ardour/midiport_manager.h @@ -0,0 +1,94 @@ +/* + Copyright (C) 1998 Paul Barton-Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __midiport_manager_h__ +#define __midiport_manager_h__ + +#include + +#include + +#include "pbd/rcu.h" + +#include "midi++/types.h" +#include "midi++/port.h" + +#include "ardour/types.h" + +namespace ARDOUR { + +class MidiPort; +class Port; + +class MidiPortManager { + public: + MidiPortManager(); + virtual ~MidiPortManager (); + + MidiPort* add_port (MidiPort *); + void remove_port (MidiPort *); + + MidiPort* port (const std::string&); + + /* Ports used for control. These are read/written to outside of the + * process callback (asynchronously with respect to when data + * actually arrives). + * + * More detail: we do actually read/write data for these ports + * inside the process callback, but incoming data is only parsed + * and outgoing data is only generated *outside* the process + * callback. + */ + + MIDI::Port* midi_input_port () { return _midi_input_port; } + MIDI::Port* midi_output_port () { return _midi_output_port; } + + /* Ports used for synchronization. These have their I/O handled inside the + * process callback. + */ + + boost::shared_ptr mtc_input_port() const { return _mtc_input_port; } + boost::shared_ptr mtc_output_port() const { return _mtc_output_port; } + 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_port_states (std::list); + + PBD::Signal0 PortsChanged; + + protected: + /* asynchronously handled ports: MIDI::Port */ + MIDI::Port* _midi_input_port; + MIDI::Port* _midi_output_port; + boost::shared_ptr _midi_in; + boost::shared_ptr _midi_out; + + /* synchronously handled ports: ARDOUR::MidiPort */ + boost::shared_ptr _mtc_input_port; + boost::shared_ptr _mtc_output_port; + boost::shared_ptr _midi_clock_input_port; + boost::shared_ptr _midi_clock_output_port; + + void create_ports (); + +}; + +} // namespace MIDI + +#endif // __midi_port_manager_h__ diff --git a/libs/ardour/midiport_manager.cc b/libs/ardour/midiport_manager.cc new file mode 100644 index 0000000000..fb27800762 --- /dev/null +++ b/libs/ardour/midiport_manager.cc @@ -0,0 +1,89 @@ +/* + Copyright (C) 1998-99 Paul Barton-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. + + $Id$ +*/ + +#include "ardour/audioengine.h" +#include "ardour/async_midi_port.h" +#include "ardour/midiport_manager.h" + +#include "i18n.h" + +using namespace ARDOUR; +using namespace std; +using namespace MIDI; +using namespace PBD; + + +MidiPortManager::MidiPortManager () +{ +} + +MidiPortManager::~MidiPortManager () +{ + if (_midi_in) { + AudioEngine::instance()->unregister_port (_midi_in); + } + if (_midi_in) { + AudioEngine::instance()->unregister_port (_midi_in); + } + if (_mtc_input_port) { + AudioEngine::instance()->unregister_port (_mtc_input_port); + } + if (_mtc_output_port) { + AudioEngine::instance()->unregister_port (_mtc_output_port); + } + if (_midi_clock_input_port) { + AudioEngine::instance()->unregister_port (_midi_clock_input_port); + } + if (_midi_clock_output_port) { + AudioEngine::instance()->unregister_port (_midi_clock_output_port); + } + +} + +MidiPort* +MidiPortManager::port (string const & n) +{ + boost::shared_ptr mp = boost::dynamic_pointer_cast (AudioEngine::instance()->get_port_by_name (n)); + return mp.get(); +} + +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); + + _midi_input_port = boost::dynamic_pointer_cast(_midi_in).get(); + _midi_output_port = boost::dynamic_pointer_cast(_midi_out).get(); +} + +void +MidiPortManager::set_port_states (list s) +{ + PortManager::PortList pl; + + AudioEngine::instance()->get_ports (DataType::MIDI, pl); + + for (list::iterator i = s.begin(); i != s.end(); ++i) { + for (PortManager::PortList::const_iterator j = pl.begin(); j != pl.end(); ++j) { + // (*j)->set_state (**i); + } + } +} + diff --git a/libs/midi++2/jack_midi_port.cc b/libs/midi++2/jack_midi_port.cc deleted file mode 100644 index 8ba27759bc..0000000000 --- a/libs/midi++2/jack_midi_port.cc +++ /dev/null @@ -1,474 +0,0 @@ -/* - Copyright (C) 1998 Paul Barton-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. - - $Id$ -*/ -#include -#include -#include -#include - -#include "pbd/xml++.h" -#include "pbd/error.h" -#include "pbd/failed_constructor.h" -#include "pbd/convert.h" -#include "pbd/strsplit.h" -#include "pbd/stacktrace.h" - -#include "midi++/types.h" -#include "midi++/jack_midi_port.h" -#include "midi++/channel.h" - -using namespace MIDI; -using namespace std; -using namespace PBD; - -namespace Evoral { -template class EventRingBuffer; -} - -pthread_t JackMIDIPort::_process_thread; -Signal0 JackMIDIPort::EngineHalted; -Signal0 JackMIDIPort::MakeConnections; - -JackMIDIPort::JackMIDIPort (string const & name, Flags flags, ARDOUR::PortEngine& pengine) - : Port (name, flags) - , _port_engine (pengine) - , _port_handle (0) - , _currently_in_cycle (false) - , _nframes_this_cycle (0) - , _last_write_timestamp (0) - , output_fifo (512) - , input_fifo (1024) - , xthread (true) -{ - init (name, flags); -} - -JackMIDIPort::JackMIDIPort (const XMLNode& node, ARDOUR::PortEngine& pengine) - : Port (node) - , _port_engine (pengine) - , _port_handle (0) - , _currently_in_cycle (false) - , _nframes_this_cycle (0) - , _last_write_timestamp (0) - , output_fifo (512) - , input_fifo (1024) - , xthread (true) -{ - Descriptor desc (node); - init (desc.tag, desc.flags); - set_state (node); -} - -void -JackMIDIPort::init (const string& /*name*/, Flags /*flags*/) -{ - if (!create_port ()) { - _ok = true; - } - - MakeConnections.connect_same_thread (connect_connection, boost::bind (&JackMIDIPort::make_connections, this)); - EngineHalted.connect_same_thread (halt_connection, boost::bind (&JackMIDIPort::engine_halted, this)); -} - - -JackMIDIPort::~JackMIDIPort () -{ - if (_port_handle) { - _port_engine.unregister_port (_port_handle); - _port_handle = 0; - } -} - -void -JackMIDIPort::parse (framecnt_t timestamp) -{ - byte buf[512]; - - /* NOTE: parsing is done (if at all) by initiating a read from - the port. Each port implementation calls on the parser - once it has data ready. - */ - - _parser->set_timestamp (timestamp); - - while (1) { - - // cerr << "+++ READ ON " << name() << endl; - - int nread = read (buf, sizeof (buf)); - - // cerr << "-- READ (" << nread << " ON " << name() << endl; - - if (nread > 0) { - if ((size_t) nread < sizeof (buf)) { - break; - } else { - continue; - } - } else if (nread == 0) { - break; - } else if (errno == EAGAIN) { - break; - } else { - fatal << "Error reading from MIDI port " << name() << endmsg; - /*NOTREACHED*/ - } - } -} - -void -JackMIDIPort::cycle_start (pframes_t nframes) -{ - assert (_port_handle); - - _currently_in_cycle = true; - _nframes_this_cycle = nframes; - - assert(_nframes_this_cycle == nframes); - - if (sends_output()) { - void *buffer = _port_engine.get_buffer (_port_handle, nframes); - jack_midi_clear_buffer (buffer); - flush (buffer); - } - - if (receives_input()) { - void* buffer = _port_engine.get_buffer (_port_handle, nframes); - const pframes_t event_count = _port_engine.get_midi_event_count (buffer); - - pframes_t time; - size_t size; - uint8_t* buf; - 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); - input_fifo.write (cycle_start_frame + time, (Evoral::EventType) 0, size, buf); - } - - if (event_count) { - xthread.wakeup (); - } - } -} - -void -JackMIDIPort::cycle_end () -{ - if (sends_output()) { - flush (_port_engine.get_buffer (_port_handle, _nframes_this_cycle)); - } - - _currently_in_cycle = false; - _nframes_this_cycle = 0; -} - -void -JackMIDIPort::engine_halted () -{ - _port_handle = 0; -} - -void -JackMIDIPort::drain (int check_interval_usecs) -{ - RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0} }; - - if (is_process_thread()) { - error << "Process thread called MIDI::JackMIDIPort::drain() - this cannot work" << endmsg; - return; - } - - while (1) { - output_fifo.get_write_vector (&vec); - if (vec.len[0] + vec.len[1] >= output_fifo.bufsize() - 1) { - break; - } - usleep (check_interval_usecs); - } -} - -int -JackMIDIPort::write (const byte * msg, size_t msglen, timestamp_t timestamp) -{ - int ret = 0; - - if (!_port_handle) { - /* poof ! make it just vanish into thin air, since we are no - longer connected to JACK. - */ - return msglen; - } - - if (!sends_output()) { - return ret; - } - - if (!is_process_thread()) { - - Glib::Threads::Mutex::Lock lm (output_fifo_lock); - RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0} }; - - output_fifo.get_write_vector (&vec); - - if (vec.len[0] + vec.len[1] < 1) { - error << "no space in FIFO for non-process thread MIDI write" << endmsg; - return 0; - } - - if (vec.len[0]) { - if (!vec.buf[0]->owns_buffer()) { - vec.buf[0]->set_buffer (0, 0, true); - } - vec.buf[0]->set (msg, msglen, timestamp); - } else { - if (!vec.buf[1]->owns_buffer()) { - vec.buf[1]->set_buffer (0, 0, true); - } - vec.buf[1]->set (msg, msglen, timestamp); - } - - output_fifo.increment_write_idx (1); - - ret = msglen; - - } else { - - if (timestamp >= _nframes_this_cycle) { - std::cerr << "attempting to write MIDI event of " << msglen << " bytes at time " - << timestamp << " of " << _nframes_this_cycle - << " (this will not work - needs a code fix)" - << std::endl; - } - - if (_currently_in_cycle) { - if (timestamp == 0) { - timestamp = _last_write_timestamp; - } - - if ((ret = _port_engine.midi_event_put (_port_engine.get_buffer (_port_handle, _nframes_this_cycle), - timestamp, msg, msglen)) == 0) { - ret = msglen; - _last_write_timestamp = timestamp; - - } else { - cerr << "write of " << msglen << " @ " << timestamp << " failed, port holds " - << _port_engine.get_midi_event_count (_port_engine.get_buffer (_port_handle, _nframes_this_cycle)) - << " port is " << _port_handle - << " ntf = " << _nframes_this_cycle - << " buf = " << _port_engine.get_buffer (_port_handle, _nframes_this_cycle) - << " ret = " << ret - << endl; - PBD::stacktrace (cerr, 20); - ret = 0; - } - } else { - cerr << "write to JACK midi port failed: not currently in a process cycle." << endl; - PBD::stacktrace (cerr, 20); - } - } - - if (ret > 0 && _parser) { - // ardour doesn't care about this and neither should your app, probably - // output_parser->raw_preparse (*output_parser, msg, ret); - for (int i = 0; i < ret; i++) { - _parser->scanner (msg[i]); - } - // ardour doesn't care about this and neither should your app, probably - // output_parser->raw_postparse (*output_parser, msg, ret); - } - - return ret; -} - -void -JackMIDIPort::flush (void* port_buffer) -{ - RingBuffer< Evoral::Event >::rw_vector vec = { { 0, 0 }, { 0, 0 } }; - size_t written; - - output_fifo.get_read_vector (&vec); - - if (vec.len[0] + vec.len[1]) { - // cerr << "Flush " << vec.len[0] + vec.len[1] << " events from non-process FIFO\n"; - } - - if (vec.len[0]) { - Evoral::Event* evp = vec.buf[0]; - - for (size_t n = 0; n < vec.len[0]; ++n, ++evp) { - _port_engine.midi_event_put (port_buffer, (timestamp_t) evp->time(), evp->buffer(), evp->size()); - } - } - - if (vec.len[1]) { - Evoral::Event* evp = vec.buf[1]; - - for (size_t n = 0; n < vec.len[1]; ++n, ++evp) { - _port_engine.midi_event_put (port_buffer, (timestamp_t) evp->time(), evp->buffer(), evp->size()); - } - } - - if ((written = vec.len[0] + vec.len[1]) != 0) { - output_fifo.increment_read_idx (written); - } -} - -int -JackMIDIPort::read (byte *, size_t) -{ - if (!receives_input()) { - return 0; - } - - timestamp_t time; - Evoral::EventType type; - uint32_t size; - byte buffer[input_fifo.capacity()]; - - while (input_fifo.read (&time, &type, &size, buffer)) { - _parser->set_timestamp (time); - for (uint32_t i = 0; i < size; ++i) { - _parser->scanner (buffer[i]); - } - } - - return 0; -} - -int -JackMIDIPort::create_port () -{ - ARDOUR::PortFlags f = ARDOUR::PortFlags (0); - - /* convert MIDI::Port::Flags to ARDOUR::PortFlags ... sigh */ - - if (_flags & IsInput) { - f = ARDOUR::PortFlags (f | ARDOUR::IsInput); - } - - if (_flags & IsOutput) { - f = ARDOUR::PortFlags (f | ARDOUR::IsOutput); - } - - _port_handle = _port_engine.register_port (_tagname, ARDOUR::DataType::MIDI, f); - - return _port_handle == 0 ? -1 : 0; -} - -XMLNode& -JackMIDIPort::get_state () const -{ - XMLNode& root = Port::get_state (); - -#if 0 - byte device_inquiry[6]; - - device_inquiry[0] = 0xf0; - device_inquiry[0] = 0x7e; - device_inquiry[0] = 0x7f; - device_inquiry[0] = 0x06; - device_inquiry[0] = 0x02; - device_inquiry[0] = 0xf7; - - write (device_inquiry, sizeof (device_inquiry), 0); -#endif - - if (_port_handle) { - - vector connections; - _port_engine.get_connections (_port_handle, connections); - string connection_string; - for (vector::iterator i = connections.begin(); i != connections.end(); ++i) { - if (i != connections.begin()) { - connection_string += ','; - } - connection_string += *i; - } - - if (!connection_string.empty()) { - root.add_property ("connections", connection_string); - } - } else { - if (!_connections.empty()) { - root.add_property ("connections", _connections); - } - } - - return root; -} - -void -JackMIDIPort::set_state (const XMLNode& node) -{ - const XMLProperty* prop; - - if ((prop = node.property ("tag")) == 0 || prop->value() != _tagname) { - return; - } - - Port::set_state (node); - - if ((prop = node.property ("connections")) != 0) { - _connections = prop->value (); - } -} - -void -JackMIDIPort::make_connections () -{ - if (!_connections.empty()) { - vector ports; - split (_connections, ports, ','); - for (vector::iterator x = ports.begin(); x != ports.end(); ++x) { - _port_engine.connect (_port_handle, *x); - /* ignore failures */ - } - } - - connect_connection.disconnect (); -} - -void -JackMIDIPort::set_process_thread (pthread_t thr) -{ - _process_thread = thr; -} - -bool -JackMIDIPort::is_process_thread() -{ - return (pthread_self() == _process_thread); -} - -void -JackMIDIPort::reestablish () -{ - int const r = create_port (); - - if (r) { - PBD::error << "could not reregister ports for " << name() << endmsg; - } -} - -void -JackMIDIPort::reconnect () -{ - make_connections (); -} diff --git a/libs/midi++2/manager.cc b/libs/midi++2/manager.cc deleted file mode 100644 index 3df9681dd3..0000000000 --- a/libs/midi++2/manager.cc +++ /dev/null @@ -1,183 +0,0 @@ -/* - Copyright (C) 1998-99 Paul Barton-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. - - $Id$ -*/ - -#include - -#include - -#include "pbd/error.h" - -#include "midi++/types.h" -#include "midi++/manager.h" -#include "midi++/channel.h" -#include "midi++/port.h" -#include "midi++/jack_midi_port.h" -#include "midi++/mmc.h" - -using namespace std; -using namespace MIDI; -using namespace PBD; - -Manager *Manager::theManager = 0; - -Manager::Manager (ARDOUR::PortEngine& eng) - : _ports (new PortList) -{ - _mmc = new MachineControl (this, eng); - - _mtc_input_port = add_port (new MIDI::JackMIDIPort ("MTC in", Port::IsInput, eng)); - _mtc_output_port = add_port (new MIDI::JackMIDIPort ("MTC out", Port::IsOutput, eng)); - _midi_input_port = add_port (new MIDI::JackMIDIPort ("MIDI control in", Port::IsInput, eng)); - _midi_output_port = add_port (new MIDI::JackMIDIPort ("MIDI control out", Port::IsOutput, eng)); - _midi_clock_input_port = add_port (new MIDI::JackMIDIPort ("MIDI clock in", Port::IsInput, eng)); - _midi_clock_output_port = add_port (new MIDI::JackMIDIPort ("MIDI clock out", Port::IsOutput, eng)); -} - -Manager::~Manager () -{ - delete _mmc; - - /* This will delete our MTC etc. ports */ - - boost::shared_ptr pr = _ports.reader (); - for (PortList::iterator p = pr->begin(); p != pr->end(); ++p) { - delete *p; - } - - if (theManager == this) { - theManager = 0; - } -} - -Port * -Manager::add_port (Port* p) -{ - { - RCUWriter writer (_ports); - boost::shared_ptr pw = writer.get_copy (); - pw->push_back (p); - } - - PortsChanged (); /* EMIT SIGNAL */ - - return p; -} - -void -Manager::remove_port (Port* p) -{ - { - RCUWriter writer (_ports); - boost::shared_ptr pw = writer.get_copy (); - pw->remove (p); - } - - PortsChanged (); /* EMIT SIGNAL */ -} - -void -Manager::cycle_start (pframes_t nframes) -{ - boost::shared_ptr pr = _ports.reader (); - - for (PortList::iterator p = pr->begin(); p != pr->end(); ++p) { - (*p)->cycle_start (nframes); - } -} - -void -Manager::cycle_end() -{ - boost::shared_ptr pr = _ports.reader (); - - for (PortList::iterator p = pr->begin(); p != pr->end(); ++p) { - (*p)->cycle_end (); - } -} - -/** Re-register ports that disappear on JACK shutdown */ -void -Manager::reestablish () -{ - boost::shared_ptr pr = _ports.reader (); - - for (PortList::const_iterator p = pr->begin(); p != pr->end(); ++p) { - JackMIDIPort* pp = dynamic_cast (*p); - if (pp) { - pp->reestablish (); - } - } -} - -/** Re-connect ports after a reestablish () */ -void -Manager::reconnect () -{ - boost::shared_ptr pr = _ports.reader (); - - for (PortList::const_iterator p = pr->begin(); p != pr->end(); ++p) { - JackMIDIPort* pp = dynamic_cast (*p); - if (pp) { - pp->reconnect (); - } - } -} - -Port* -Manager::port (string const & n) -{ - boost::shared_ptr pr = _ports.reader (); - - PortList::const_iterator p = pr->begin(); - while (p != pr->end() && (*p)->name() != n) { - ++p; - } - - if (p == pr->end()) { - return 0; - } - - return *p; -} - -void -Manager::create (ARDOUR::PortEngine& eng) -{ - assert (theManager == 0); - theManager = new Manager (eng); -} - -void -Manager::set_port_states (list s) -{ - boost::shared_ptr pr = _ports.reader (); - - for (list::iterator i = s.begin(); i != s.end(); ++i) { - for (PortList::const_iterator j = pr->begin(); j != pr->end(); ++j) { - (*j)->set_state (**i); - } - } -} - -void -Manager::destroy () -{ - delete theManager; - theManager = 0; -} diff --git a/libs/midi++2/midi++/jack_midi_port.h b/libs/midi++2/midi++/jack_midi_port.h deleted file mode 100644 index 492756067c..0000000000 --- a/libs/midi++2/midi++/jack_midi_port.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - Copyright (C) 1998-2010 Paul Barton-Davis - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __libmidi_port_h__ -#define __libmidi_port_h__ - -#include -#include - -#include "pbd/xml++.h" -#include "pbd/crossthread.h" -#include "pbd/signals.h" -#include "pbd/ringbuffer.h" - -#include "evoral/Event.hpp" -#include "evoral/EventRingBuffer.hpp" - -#include "midi++/types.h" -#include "midi++/parser.h" -#include "midi++/port.h" - -#include "ardour/port_engine.h" - -namespace MIDI { - -class Channel; -class PortRequest; - -class JackMIDIPort : public Port { - public: - JackMIDIPort (std::string const &, Port::Flags, ARDOUR::PortEngine&); - JackMIDIPort (const XMLNode&, ARDOUR::PortEngine&); - ~JackMIDIPort (); - - XMLNode& get_state () const; - void set_state (const XMLNode&); - - void cycle_start (pframes_t nframes); - void cycle_end (); - - void parse (framecnt_t timestamp); - int write (const byte *msg, size_t msglen, timestamp_t timestamp); - int read (byte *buf, size_t bufsize); - void drain (int check_interval_usecs); - int selectable () const { return xthread.selectable(); } - - pframes_t nframes_this_cycle() const { return _nframes_this_cycle; } - - void reestablish (); - void reconnect (); - - static void set_process_thread (pthread_t); - static pthread_t get_process_thread () { return _process_thread; } - static bool is_process_thread(); - - static PBD::Signal0 MakeConnections; - static PBD::Signal0 EngineHalted; - -private: - ARDOUR::PortEngine& _port_engine; - ARDOUR::PortEngine::PortHandle _port_handle; - - bool _currently_in_cycle; - pframes_t _nframes_this_cycle; - timestamp_t _last_write_timestamp; - RingBuffer< Evoral::Event > output_fifo; - Evoral::EventRingBuffer input_fifo; - Glib::Threads::Mutex output_fifo_lock; - CrossThreadChannel xthread; - - int create_port (); - - /** Channel used to signal to the MidiControlUI that input has arrived */ - - std::string _connections; - PBD::ScopedConnection connect_connection; - PBD::ScopedConnection halt_connection; - void flush (void* port_buffer); - void engine_halted (); - void make_connections (); - void init (std::string const &, Flags); - - static pthread_t _process_thread; - -}; - -} // namespace MIDI - -#endif // __libmidi_port_h__ diff --git a/libs/midi++2/midi++/manager.h b/libs/midi++2/midi++/manager.h deleted file mode 100644 index 7f4df5c6c8..0000000000 --- a/libs/midi++2/midi++/manager.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - Copyright (C) 1998 Paul Barton-Davis - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef __midi_manager_h__ -#define __midi_manager_h__ - -#include - -#include - -#include "pbd/rcu.h" - -#include "midi++/types.h" -#include "midi++/port.h" - -namespace ARDOUR { - class PortEngine; -} - -namespace MIDI { - -class MachineControl; - -class Manager { - public: - ~Manager (); - - /** 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 (); - - MachineControl* mmc () const { return _mmc; } - Port *mtc_input_port() const { return _mtc_input_port; } - Port *mtc_output_port() const { return _mtc_output_port; } - Port *midi_input_port() const { return _midi_input_port; } - Port *midi_output_port() const { return _midi_output_port; } - Port *midi_clock_input_port() const { return _midi_clock_input_port; } - Port *midi_clock_output_port() const { return _midi_clock_output_port; } - - Port* add_port (Port *); - void remove_port (Port *); - - Port* port (std::string const &); - - void set_port_states (std::list); - - typedef std::list PortList; - - boost::shared_ptr get_midi_ports() const { return _ports.reader (); } - - static void create (ARDOUR::PortEngine&); - - static Manager *instance () { - return theManager; - } - static void destroy (); - - void reestablish (); - void reconnect (); - - PBD::Signal0 PortsChanged; - - private: - /* This is a SINGLETON pattern */ - - Manager (ARDOUR::PortEngine&); - static Manager *theManager; - - MIDI::MachineControl* _mmc; - MIDI::Port* _mtc_input_port; - MIDI::Port* _mtc_output_port; - MIDI::Port* _midi_input_port; - MIDI::Port* _midi_output_port; - MIDI::Port* _midi_clock_input_port; - MIDI::Port* _midi_clock_output_port; - - SerializedRCUManager _ports; -}; - -} // namespace MIDI - -#endif // __midi_manager_h__ -- 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/midi++2') 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 a5a3f713d596fd3d0157017263d6207b5427d133 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Mon, 12 Aug 2013 05:40:11 -0400 Subject: assorted extra debug output for MTC --- libs/ardour/midi_port.cc | 4 +++- libs/ardour/mtc_slave.cc | 8 +++++++- libs/midi++2/mtc.cc | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) (limited to 'libs/midi++2') diff --git a/libs/ardour/midi_port.cc b/libs/ardour/midi_port.cc index 5589c6e501..1816ddcb6f 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -71,7 +71,9 @@ MidiPort::get_midi_buffer (pframes_t nframes) /* suck all relevant MIDI events from the MIDI port buffer into our MidiBuffer */ - + + cerr << "grabbing " << event_count << " events\n"; + for (pframes_t i = 0; i < event_count; ++i) { pframes_t timestamp; diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index 80d89d6215..7f68e54f4b 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -106,6 +106,8 @@ MTC_Slave::process (pframes_t nframes) /* dump incoming MIDI to parser */ + cerr << "\n\n\n<<<< MTC slave, process " << mb.size() << endl; + for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) { uint8_t* buf = (*b).buffer(); @@ -113,11 +115,15 @@ MTC_Slave::process (pframes_t nframes) uint32_t limit = (*b).size(); + cerr << "msg of " << limit << " bytes\n"; + for (size_t n = 0; n < limit; ++n) { parser.scanner (buf[n]); } } + cerr << ">>>> MTC slave, done processing\n\n\n"; + return 0; } @@ -331,7 +337,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now) a locate command via MMC. */ - //DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", ::pthread_self())); + DEBUG_TRACE (DEBUG::MTC, string_compose ("MTC::update_mtc_time - TID:%1\n", ::pthread_self())); TimecodeFormat tc_format; bool reset_tc = true; diff --git a/libs/midi++2/mtc.cc b/libs/midi++2/mtc.cc index affe65ec68..57c78cbfb0 100644 --- a/libs/midi++2/mtc.cc +++ b/libs/midi++2/mtc.cc @@ -33,7 +33,7 @@ using namespace std; using namespace sigc; using namespace MIDI; -#undef DEBUG_MTC +#define DEBUG_MTC bool Parser::possible_mtc (byte *sysex_buf, size_t msglen) @@ -240,7 +240,7 @@ Parser::process_mtc_quarter_frame (byte *msg) /* time code is looking good */ #ifdef DEBUG_MTC - // cerr << "for quarter frame " << which_quarter_frame << " byte = " << hex << (int) msg[1] << dec << endl; + cerr << "for quarter frame " << which_quarter_frame << " byte = " << hex << (int) msg[1] << dec << endl; #endif switch (which_quarter_frame) { -- cgit v1.2.3 From a5a75d5e0d4fb9f2c7db7cf3747da2314c2f9586 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Tue, 13 Aug 2013 12:53:28 -0400 Subject: fixes to get MTC (and probably MIDI clock) slaving working again incoming MIDI data has to be parsed EVERY process cycle, not just when Slave::speed_and_position() is called. The private MIDI::Parser owned by the MTC and MClck slaves was irrelevant, since the port has its own. See comments in midi_port.h on the strangled inheritance heirarchy. --- libs/ardour/ardour/midi_port.h | 23 +++++++++++-- libs/ardour/ardour/slave.h | 14 -------- libs/ardour/midi_clock_slave.cc | 39 ++++++---------------- libs/ardour/midi_port.cc | 29 +++++++++++++++-- libs/ardour/midiport_manager.cc | 9 ++++++ libs/ardour/mtc_slave.cc | 71 +++++++++++++++-------------------------- libs/ardour/session_process.cc | 1 - libs/midi++2/mtc.cc | 2 +- 8 files changed, 92 insertions(+), 96 deletions(-) (limited to 'libs/midi++2') diff --git a/libs/ardour/ardour/midi_port.h b/libs/ardour/ardour/midi_port.h index 14dc6cd021..00617d90ec 100644 --- a/libs/ardour/ardour/midi_port.h +++ b/libs/ardour/ardour/midi_port.h @@ -21,6 +21,8 @@ #ifndef __ardour_midi_port_h__ #define __ardour_midi_port_h__ +#include "midi++/parser.h" + #include "ardour/port.h" #include "ardour/midi_buffer.h" #include "ardour/midi_state_tracker.h" @@ -56,16 +58,33 @@ class MidiPort : public Port { MidiBuffer& get_midi_buffer (pframes_t nframes); + void set_always_parse (bool yn); + MIDI::Parser& self_parser() { return _self_parser; } + protected: - friend class PortManager; + friend class PortManager; - MidiPort (const std::string& name, PortFlags); + MidiPort (const std::string& name, PortFlags); private: MidiBuffer* _buffer; bool _has_been_mixed_down; bool _resolve_required; bool _input_active; + bool _always_parse; + + /* Naming this is tricky. AsyncMIDIPort inherits (for now, aug 2013) from + * both MIDI::Port, which has _parser, and this (ARDOUR::MidiPort). We + * need parsing support in this object, independently of what the + * MIDI::Port/AsyncMIDIPort stuff does. Rather than risk errors coming + * from not explicitly naming which _parser we want, we will call this + * _self_parser for now. + * + * Ultimately, MIDI::Port should probably go away or be fully integrated + * into this object, somehow. + */ + + MIDI::Parser _self_parser; void resolve_notes (void* buffer, MidiBuffer::TimeType when); }; diff --git a/libs/ardour/ardour/slave.h b/libs/ardour/ardour/slave.h index 1d8a7dd965..c60acb1df7 100644 --- a/libs/ardour/ardour/slave.h +++ b/libs/ardour/ardour/slave.h @@ -64,15 +64,6 @@ 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. @@ -263,7 +254,6 @@ class MTC_Slave : public TimecodeSlave { ~MTC_Slave (); void rebind (MidiPort&); - int process (pframes_t); bool speed_and_position (double&, framepos_t&); bool locked() const; @@ -282,7 +272,6 @@ class MTC_Slave : public TimecodeSlave { private: Session& session; MidiPort* port; - MIDI::Parser parser; PBD::ScopedConnectionList port_connections; PBD::ScopedConnection config_connection; bool can_notify_on_unknown_rate; @@ -420,7 +409,6 @@ class MIDIClock_Slave : public Slave { ~MIDIClock_Slave (); void rebind (MidiPort&); - int process (pframes_t); bool speed_and_position (double&, framepos_t&); bool locked() const; @@ -436,8 +424,6 @@ class MIDIClock_Slave : public Slave { protected: ISlaveSessionProxy* session; - 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/midi_clock_slave.cc b/libs/ardour/midi_clock_slave.cc index 752644e9f4..7eaeeb9e07 100644 --- a/libs/ardour/midi_clock_slave.cc +++ b/libs/ardour/midi_clock_slave.cc @@ -50,13 +50,6 @@ MIDIClock_Slave::MIDIClock_Slave (Session& s, MidiPort& p, int ppqn) 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) @@ -72,33 +65,19 @@ MIDIClock_Slave::~MIDIClock_Slave() delete session; } -int -MIDIClock_Slave::process (pframes_t nframes) +void +MIDIClock_Slave::rebind (MidiPort& port) { - MidiBuffer& mb (port->get_midi_buffer (nframes)); + DEBUG_TRACE (DEBUG::MidiClock, string_compose ("MIDIClock_Slave: connecting to port %1\n", port.name())); - /* dump incoming MIDI to parser */ + port_connections.drop_connections (); - for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) { - uint8_t* buf = (*b).buffer(); + port.self_parser().timing.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::update_midi_clock, this, _1, _2)); + port.self_parser().start.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::start, this, _1, _2)); + port.self_parser().contineu.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::contineu, this, _1, _2)); + port.self_parser().stop.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::stop, this, _1, _2)); + port.self_parser().position.connect_same_thread (port_connections, boost::bind (&MIDIClock_Slave::position, this, _1, _2, 3)); - 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 -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_port.cc b/libs/ardour/midi_port.cc index 1816ddcb6f..eb6759f308 100644 --- a/libs/ardour/midi_port.cc +++ b/libs/ardour/midi_port.cc @@ -33,6 +33,7 @@ MidiPort::MidiPort (const std::string& name, PortFlags flags) , _has_been_mixed_down (false) , _resolve_required (false) , _input_active (true) + , _always_parse (false) { _buffer = new MidiBuffer (AudioEngine::instance()->raw_buffer_size (DataType::MIDI)); } @@ -45,6 +46,8 @@ MidiPort::~MidiPort() void MidiPort::cycle_start (pframes_t nframes) { + framepos_t now = AudioEngine::instance()->sample_time_at_cycle_start(); + Port::cycle_start (nframes); _buffer->clear (); @@ -52,6 +55,24 @@ MidiPort::cycle_start (pframes_t nframes) if (sends_output ()) { port_engine.midi_clear (port_engine.get_buffer (_port_handle, nframes)); } + + if (_always_parse) { + MidiBuffer& mb (get_midi_buffer (nframes)); + + /* dump incoming MIDI to parser */ + + for (MidiBuffer::iterator b = mb.begin(); b != mb.end(); ++b) { + uint8_t* buf = (*b).buffer(); + + _self_parser.set_timestamp (now + (*b).time()); + + uint32_t limit = (*b).size(); + + for (size_t n = 0; n < limit; ++n) { + _self_parser.scanner (buf[n]); + } + } + } } MidiBuffer & @@ -72,8 +93,6 @@ MidiPort::get_midi_buffer (pframes_t nframes) into our MidiBuffer */ - cerr << "grabbing " << event_count << " events\n"; - for (pframes_t i = 0; i < event_count; ++i) { pframes_t timestamp; @@ -217,3 +236,9 @@ MidiPort::set_input_active (bool yn) { _input_active = yn; } + +void +MidiPort::set_always_parse (bool yn) +{ + _always_parse = yn; +} diff --git a/libs/ardour/midiport_manager.cc b/libs/ardour/midiport_manager.cc index a4d53d6530..5d4e8e37f6 100644 --- a/libs/ardour/midiport_manager.cc +++ b/libs/ardour/midiport_manager.cc @@ -107,6 +107,15 @@ MidiPortManager::create_ports () _midi_clock_input_port = boost::dynamic_pointer_cast (p); p = AudioEngine::instance()->register_output_port (DataType::MIDI, _("MIDI Clock out")); _midi_clock_output_port= boost::dynamic_pointer_cast (p); + + /* These ports all need their incoming data handled in + * Port::cycle_start() and so ... + */ + + _mtc_input_port->set_always_parse (true); + _mtc_output_port->set_always_parse (true); + _midi_clock_input_port->set_always_parse (true); + _midi_clock_output_port->set_always_parse (true); } void diff --git a/libs/ardour/mtc_slave.cc b/libs/ardour/mtc_slave.cc index 7f68e54f4b..e9071af619 100644 --- a/libs/ardour/mtc_slave.cc +++ b/libs/ardour/mtc_slave.cc @@ -73,10 +73,9 @@ MTC_Slave::MTC_Slave (Session& s, MidiPort& p) parse_timecode_offset(); reset (true); - 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)); - + port->self_parser().mtc_time.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_time, this, _1, _2, _3)); + port->self_parser().mtc_qtr.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_qtr, this, _1, _2, _3)); + port->self_parser().mtc_status.connect_same_thread (port_connections, boost::bind (&MTC_Slave::update_mtc_status, this, _1)); } MTC_Slave::~MTC_Slave() @@ -99,34 +98,6 @@ MTC_Slave::~MTC_Slave() } } -int -MTC_Slave::process (pframes_t nframes) -{ - MidiBuffer& mb (port->get_midi_buffer (nframes)); - - /* dump incoming MIDI to parser */ - - cerr << "\n\n\n<<<< MTC slave, process " << mb.size() << endl; - - 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(); - - cerr << "msg of " << limit << " bytes\n"; - - for (size_t n = 0; n < limit; ++n) { - parser.scanner (buf[n]); - } - } - - cerr << ">>>> MTC slave, done processing\n\n\n"; - - return 0; -} - void MTC_Slave::rebind (MidiPort& p) { @@ -185,7 +156,8 @@ MTC_Slave::outside_window (framepos_t pos) const bool MTC_Slave::locked () const { - return parser.mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0; + DEBUG_TRACE (DEBUG::MTC, string_compose ("locked ? %1 last %2 initstate %3\n", port->self_parser().mtc_locked(), last_inbound_frame, engine_dll_initstate)); + return port->self_parser().mtc_locked() && last_inbound_frame !=0 && engine_dll_initstate !=0; } bool @@ -286,7 +258,6 @@ MTC_Slave::init_mtc_dll(framepos_t tme, double qtr) DEBUG_TRACE (DEBUG::MTC, string_compose ("[re-]init MTC DLL %1 %2 %3\n", t0, t1, e2)); } - /* called from MIDI parser */ void MTC_Slave::update_mtc_qtr (Parser& /*p*/, int which_qtr, framepos_t now) @@ -453,7 +424,7 @@ MTC_Slave::update_mtc_time (const byte *msg, bool was_full, framepos_t now) now, timecode, mtc_frame, was_full, speedup_due_to_tc_mismatch)); if (was_full || outside_window (mtc_frame)) { - DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC or outside window. - TID:%1\n", ::pthread_self())); + DEBUG_TRACE (DEBUG::MTC, string_compose ("update_mtc_time: full TC %1 or outside window %2\n", was_full, outside_window (mtc_frame))); session.request_locate (mtc_frame, false); session.request_transport_speed (0); update_mtc_status (MIDI::MTC_Stopped); @@ -477,7 +448,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 (parser.mtc_running()) { + switch (port->self_parser().mtc_running()) { case MTC_Backward: mtc_frame -= mtc_off; qtr *= -1.0; @@ -557,9 +528,10 @@ MTC_Slave::reset_window (framepos_t root) of acceptable MTC frames wide open. otherwise, shrink it down to just 2 video frames ahead of the window root (taking direction into account). */ + framecnt_t const d = (quarter_frame_duration * 4 * frame_tolerance); - switch (parser.mtc_running()) { + switch (port->self_parser().mtc_running()) { case MTC_Forward: window_begin = root; transport_direction = 1; @@ -582,7 +554,7 @@ MTC_Slave::reset_window (framepos_t root) break; } - DEBUG_TRACE (DEBUG::MTC, string_compose ("legal MTC window now %1 .. %2\n", window_begin, window_end)); + DEBUG_TRACE (DEBUG::MTC, string_compose ("reset MTC window @ %3, now %1 .. %2\n", window_begin, window_end, root)); } void @@ -620,9 +592,19 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos) read_current (&last); + DEBUG_TRACE (DEBUG::MTC, string_compose ("speed&pos: timestamp %1 speed %2 initstate %3 dir %4 tpos %5 now %6 last-in %7\n", + last.timestamp, + last.speed, + engine_dll_initstate, + transport_direction, + sess_pos, + now, + last_inbound_frame)); + /* re-init engine DLL here when state changed (direction, first_mtc_timestamp) */ - if (last.timestamp == 0) { engine_dll_initstate = 0; } - else if (engine_dll_initstate != transport_direction && last.speed != 0) { + if (last.timestamp == 0) { + engine_dll_initstate = 0; + } else if (engine_dll_initstate != transport_direction && last.speed != 0) { engine_dll_initstate = transport_direction; init_engine_dll(last.position, session.engine().samples_per_cycle()); engine_dll_reinitialized = true; @@ -656,9 +638,7 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos) /* interpolate position according to speed and time since last quarter-frame*/ if (speed_flt == 0.0f) { elapsed = 0; - } - else - { + } else { /* scale elapsed time by the current MTC speed */ elapsed = (framecnt_t) rint (speed_flt * (now - last.timestamp)); if (give_slave_full_control_over_transport_speed() && !engine_dll_reinitialized) { @@ -688,14 +668,13 @@ MTC_Slave::speed_and_position (double& speed, framepos_t& pos) */ if (!session.actively_recording() && speed != 0 - && ( (pos < 0) || (labs(pos - sess_pos) > 3 * session.frame_rate()) ) - ) { + && ((pos < 0) || (labs(pos - sess_pos) > 3 * session.frame_rate()))) { engine_dll_initstate = 0; queue_reset (false); } /* provide a .1% deadzone to lock the speed */ - if (fabs(speed - 1.0) <= 0.001) + if (fabs (speed - 1.0) <= 0.001) speed = 1.0; DEBUG_TRACE (DEBUG::MTC, string_compose ("MTCsync spd: %1 pos: %2 | last-pos: %3 elapsed: %4 delta: %5\n", diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index 6a24198bec..3c46a2e0a6 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -491,7 +491,6 @@ 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/midi++2/mtc.cc b/libs/midi++2/mtc.cc index 57c78cbfb0..0c2d8a41b3 100644 --- a/libs/midi++2/mtc.cc +++ b/libs/midi++2/mtc.cc @@ -33,7 +33,7 @@ using namespace std; using namespace sigc; using namespace MIDI; -#define DEBUG_MTC +#undef DEBUG_MTC bool Parser::possible_mtc (byte *sysex_buf, size_t msglen) -- cgit v1.2.3