From 8a06e6735d058cb132ef6f75df550353e2e0b70e Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Sun, 19 Jun 2016 23:41:26 -0400 Subject: [PATCH] add initial implementation of a "shadow port" for AsyncMIDIPort. The shadow port is a secondary port that can be used to allow others to get a copy of part, all or none of the MIDI stream received by the owner (input) port. --- libs/ardour/ardour/async_midi_port.h | 8 ++++- libs/ardour/async_midi_port.cc | 50 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/libs/ardour/ardour/async_midi_port.h b/libs/ardour/ardour/async_midi_port.h index 96a50ab198..931c404727 100644 --- a/libs/ardour/ardour/async_midi_port.h +++ b/libs/ardour/ardour/async_midi_port.h @@ -73,6 +73,9 @@ class LIBARDOUR_API AsyncMIDIPort : public ARDOUR::MidiPort, public MIDI::Port { int selectable() const { return -1; } void set_timer (boost::function&); + void set_inbound_filter (boost::function); + int add_shadow_port (std::string const &); + static void set_process_thread (pthread_t); static pthread_t get_process_thread () { return _process_thread; } static bool is_process_thread(); @@ -99,7 +102,10 @@ class LIBARDOUR_API AsyncMIDIPort : public ARDOUR::MidiPort, public MIDI::Port { void make_connections (); void init (std::string const &, Flags); - void flush_output_fifo (pframes_t); + void flush_output_fifo (pframes_t); + + boost::shared_ptr shadow_port; + boost::function inbound_midi_filter; static pthread_t _process_thread; }; diff --git a/libs/ardour/async_midi_port.cc b/libs/ardour/async_midi_port.cc index bbcc0aab85..ff9a920c69 100644 --- a/libs/ardour/async_midi_port.cc +++ b/libs/ardour/async_midi_port.cc @@ -41,6 +41,30 @@ pthread_t AsyncMIDIPort::_process_thread; #define port_engine AudioEngine::instance()->port_engine() +static bool +filter_relax (MidiBuffer& in, MidiBuffer& out) +{ + return false; +} + +static bool +filter_copy (MidiBuffer& in, MidiBuffer& out) +{ + out.copy (in); + return false; +} + +static bool +filter_notes_only (MidiBuffer& in, MidiBuffer& out) +{ + for (MidiBuffer::iterator b = in.begin(); b != in.end(); ++b) { + if ((*b).is_note_on() || (*b).is_note_off()) { + out.push_back (*b); + } + } + return false; +} + AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags) : MidiPort (name, flags) , MIDI::Port (name, MIDI::Port::Flags (0)) @@ -50,6 +74,7 @@ AsyncMIDIPort::AsyncMIDIPort (string const & name, PortFlags flags) , output_fifo (2048) , input_fifo (1024) , _xthread (true) + , inbound_midi_filter (boost::bind (filter_notes_only, _1, _2)) { } @@ -145,6 +170,12 @@ AsyncMIDIPort::cycle_start (MIDI::pframes_t nframes) if (!mb.empty()) { _xthread.wakeup (); } + + if (shadow_port) { + inbound_midi_filter (mb, shadow_port->get_midi_buffer (nframes)); + } else { + inbound_midi_filter (mb, mb); + } } } @@ -341,3 +372,22 @@ AsyncMIDIPort::is_process_thread() return pthread_equal (pthread_self(), _process_thread); } +int +AsyncMIDIPort::add_shadow_port (string const & name) +{ + if (!ARDOUR::Port::receives_input()) { + return -1; + } + + if (shadow_port) { + return -2; + } + + /* shadow port is not async. */ + + if (!(shadow_port = boost::dynamic_pointer_cast (AudioEngine::instance()->register_output_port (DataType::MIDI, name, false)))) { + return -3; + } + + return 0; +} -- 2.30.2