13
0

give MackieControlProtocol its own thread and make it parse incoming MIDI in that thread, as well as doing timeouts there too

git-svn-id: svn://localhost/ardour2/branches/3.0@11872 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2012-04-10 17:13:55 +00:00
parent 893b468858
commit 01c1eeb279
5 changed files with 116 additions and 29 deletions

View File

@ -135,6 +135,7 @@ MidiControlUI::reset_ports ()
for (MIDI::Manager::PortList::const_iterator i = plist->begin(); i != plist->end(); ++i) {
if (!(*i)->centrally_parsed()) {
cerr << "Skip MIDI port " << (*i)->name() << endl;
continue;
}

View File

@ -42,7 +42,6 @@
#include "ardour/dB.h"
#include "ardour/debug.h"
#include "ardour/location.h"
#include "ardour/midi_ui.h"
#include "ardour/meter.h"
#include "ardour/panner.h"
#include "ardour/panner_shell.h"
@ -71,22 +70,23 @@ using namespace ARDOUR;
using namespace std;
using namespace Mackie;
using namespace PBD;
using namespace Glib;
#include "i18n.h"
#include "pbd/abstract_ui.cc" // instantiate template
#define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
#define ui_bind(f, ...) boost::protect (boost::bind (f, __VA_ARGS__))
extern PBD::EventLoop::InvalidationRecord* __invalidator (sigc::trackable& trackable, const char*, int);
#define invalidator(x) __invalidator (*(MidiControlUI::instance()), __FILE__, __LINE__)
#define invalidator() __invalidator ((*this), __FILE__, __LINE__)
const int MackieControlProtocol::MODIFIER_OPTION = 0x1;
const int MackieControlProtocol::MODIFIER_CONTROL = 0x2;
const int MackieControlProtocol::MODIFIER_SHIFT = 0x3;
const int MackieControlProtocol::MODIFIER_CMDALT = 0x4;
MackieControlProtocol* MackieControlProtocol::_instance = 0;
bool MackieControlProtocol::probe()
{
return true;
@ -107,9 +107,11 @@ MackieControlProtocol::MackieControlProtocol (Session& session)
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::MackieControlProtocol\n");
AudioEngine::instance()->PortConnectedOrDisconnected.connect (
audio_engine_connections, invalidator (*this), ui_bind (&MackieControlProtocol::port_connected_or_disconnected, this, _2, _4, _5),
midi_ui_context ()
audio_engine_connections, invalidator (), ui_bind (&MackieControlProtocol::port_connected_or_disconnected, this, _2, _4, _5),
this
);
_instance = this;
}
MackieControlProtocol::~MackieControlProtocol()
@ -129,13 +131,26 @@ MackieControlProtocol::~MackieControlProtocol()
}
DEBUG_TRACE (DEBUG::MackieControl, "finished ~MackieControlProtocol::MackieControlProtocol\n");
_instance = 0;
}
void
MackieControlProtocol::thread_init ()
{
struct sched_param rtparam;
pthread_set_name (X_("MackieControl"));
PBD::notify_gui_about_thread_creation (X_("gui"), pthread_self(), X_("MackieControl"), 2048);
ARDOUR::SessionEvent::create_per_thread_pool (X_("MackieControl"), 128);
memset (&rtparam, 0, sizeof (rtparam));
rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */
if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) {
// do we care? not particularly.
}
}
// go to the previous track.
@ -307,6 +322,10 @@ MackieControlProtocol::set_active (bool yn)
{
if (yn) {
/* start event loop */
BaseUI::run ();
create_surfaces ();
connect_session_signals ();
@ -432,23 +451,23 @@ void
MackieControlProtocol::connect_session_signals()
{
// receive routes added
session->RouteAdded.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_route_added, this, _1), midi_ui_context());
session->RouteAdded.connect(session_connections, invalidator(), ui_bind (&MackieControlProtocol::notify_route_added, this, _1), this);
// receive record state toggled
session->RecordStateChanged.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_record_state_changed, this), midi_ui_context());
session->RecordStateChanged.connect(session_connections, invalidator(), ui_bind (&MackieControlProtocol::notify_record_state_changed, this), this);
// receive transport state changed
session->TransportStateChange.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_transport_state_changed, this), midi_ui_context());
session->TransportStateChange.connect(session_connections, invalidator(), ui_bind (&MackieControlProtocol::notify_transport_state_changed, this), this);
// receive punch-in and punch-out
Config->ParameterChanged.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
session->config.ParameterChanged.connect (session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), midi_ui_context());
Config->ParameterChanged.connect(session_connections, invalidator(), ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), this);
session->config.ParameterChanged.connect (session_connections, invalidator(), ui_bind (&MackieControlProtocol::notify_parameter_changed, this, _1), this);
// receive rude solo changed
session->SoloActive.connect(session_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_solo_active_changed, this, _1), midi_ui_context());
session->SoloActive.connect(session_connections, invalidator(), ui_bind (&MackieControlProtocol::notify_solo_active_changed, this, _1), this);
// make sure remote id changed signals reach here
// see also notify_route_added
Sorted sorted = get_sorted_routes();
for (Sorted::iterator it = sorted.begin(); it != sorted.end(); ++it) {
(*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind(&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
(*it)->RemoteControlIDChanged.connect (route_connections, invalidator(), ui_bind(&MackieControlProtocol::notify_remote_id_changed, this), this);
}
}
@ -480,12 +499,29 @@ MackieControlProtocol::create_surfaces ()
ARDOUR::DataType::MIDI,
session->engine().make_port_name_non_relative (surface->port().output_port().name())
);
int fd;
MIDI::Port& input_port (surface->port().input_port());
if ((fd = input_port.selectable ()) >= 0) {
Glib::RefPtr<IOSource> psrc = IOSource::create (fd, IO_IN|IO_HUP|IO_ERR);
psrc->connect (sigc::bind (sigc::mem_fun (this, &MackieControlProtocol::midi_input_handler), &input_port));
psrc->attach (main_loop()->get_context());
// glibmm hack: for now, store only the GSource*
port_sources.push_back (psrc->gobj());
g_source_ref (psrc->gobj());
}
}
}
void
MackieControlProtocol::close()
{
clear_ports ();
port_connections.drop_connections ();
session_connections.drop_connections ();
route_connections.drop_connections ();
@ -658,7 +694,7 @@ MackieControlProtocol::notify_route_added (ARDOUR::RouteList & rl)
typedef ARDOUR::RouteList ARS;
for (ARS::iterator it = rl.begin(); it != rl.end(); ++it) {
(*it)->RemoteControlIDChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&MackieControlProtocol::notify_remote_id_changed, this), midi_ui_context());
(*it)->RemoteControlIDChanged.connect (route_connections, invalidator(), ui_bind (&MackieControlProtocol::notify_remote_id_changed, this), this);
}
}
@ -757,7 +793,7 @@ MackieControlProtocol::do_request (MackieControlUIRequest* req)
{
if (req->type == CallSlot) {
call_slot (MISSING_INVALIDATOR, req->the_slot);
call_slot (invalidator(), req->the_slot);
} else if (req->type == Quit) {
@ -787,7 +823,7 @@ MackieControlProtocol::add_in_use_timeout (Surface& surface, Control& in_use_con
sigc::bind (sigc::mem_fun (*this, &MackieControlProtocol::control_in_use_timeout), &surface, &in_use_control, touch_control));
in_use_control.in_use_touch_control = touch_control;
timeout->attach (MidiControlUI::instance()->main_loop()->get_context());
timeout->attach (main_loop()->get_context());
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("timeout queued for surface %1, control %2 touch control %3\n",
surface.number(), &in_use_control, touch_control));}
@ -1369,3 +1405,35 @@ MackieControlProtocol::select_track (boost::shared_ptr<Route> r)
}
}
bool
MackieControlProtocol::midi_input_handler (IOCondition ioc, MIDI::Port* port)
{
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", port->name()));
if (ioc & ~IO_IN) {
return false;
}
if (ioc & IO_IN) {
CrossThreadChannel::drain (port->selectable());
DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", port->name()));
framepos_t now = session->engine().frame_time();
port->parse (now);
}
return true;
}
void
MackieControlProtocol::clear_ports ()
{
for (PortSources::iterator i = port_sources.begin(); i != port_sources.end(); ++i) {
g_source_destroy (*i);
g_source_unref (*i);
}
port_sources.clear ();
}

View File

@ -84,6 +84,8 @@ class MackieControlProtocol
MackieControlProtocol(ARDOUR::Session &);
virtual ~MackieControlProtocol();
static MackieControlProtocol* instance() { return _instance; }
int set_active (bool yn);
XMLNode& get_state ();
@ -315,6 +317,8 @@ class MackieControlProtocol
private:
static MackieControlProtocol* _instance;
void create_surfaces ();
void port_connected_or_disconnected (std::string, std::string, bool);
bool control_in_use_timeout (Mackie::Surface*, Mackie::Control *, Mackie::Control *);
@ -364,6 +368,13 @@ class MackieControlProtocol
int _modifier_state;
Mackie::MackieMidiBuilder builder;
typedef std::list<GSource*> PortSources;
PortSources port_sources;
bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
void clear_ports ();
};
#endif // ardour_mackie_control_protocol_h

View File

@ -51,11 +51,11 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
#define midi_ui_context() ARDOUR::MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
#define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
#define ui_bind(f, ...) boost::protect (boost::bind (f, __VA_ARGS__))
extern PBD::EventLoop::InvalidationRecord* __invalidator (sigc::trackable& trackable, const char*, int);
#define invalidator(x) __invalidator (*(MidiControlUI::instance()), __FILE__, __LINE__)
#define invalidator() __invalidator (*(MackieControlProtocol::instance()), __FILE__, __LINE__)
Strip::Strip (Surface& s, const std::string& name, int index, StripControlDefinition* ctls)
: Group (name)
@ -237,34 +237,34 @@ Strip::set_route (boost::shared_ptr<Route> r)
if (has_solo()) {
_route->solo_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_solo_changed, this), midi_ui_context());
_route->solo_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_solo_changed, this), ui_context());
}
if (has_mute()) {
_route->mute_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_mute_changed, this), midi_ui_context());
_route->mute_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_mute_changed, this), ui_context());
}
if (has_gain()) {
_route->gain_control()->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_gain_changed, this, false), midi_ui_context());
_route->gain_control()->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_gain_changed, this, false), ui_context());
}
_route->PropertyChanged.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_property_changed, this, _1), midi_ui_context());
_route->PropertyChanged.connect (route_connections, invalidator(), ui_bind (&Strip::notify_property_changed, this, _1), ui_context());
if (_route->pannable()) {
_route->pannable()->pan_azimuth_control->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_panner_changed, this, false), midi_ui_context());
_route->pannable()->pan_width_control->Changed.connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_panner_changed, this, false), midi_ui_context());
_route->pannable()->pan_azimuth_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_changed, this, false), ui_context());
_route->pannable()->pan_width_control->Changed.connect(route_connections, invalidator(), ui_bind (&Strip::notify_panner_changed, this, false), ui_context());
}
boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<ARDOUR::Track>(_route);
if (trk) {
trk->rec_enable_control()->Changed .connect(route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_record_enable_changed, this), midi_ui_context());
trk->rec_enable_control()->Changed .connect(route_connections, invalidator(), ui_bind (&Strip::notify_record_enable_changed, this), ui_context());
}
// TODO this works when a currently-banked route is made inactive, but not
// when a route is activated which should be currently banked.
_route->active_changed.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_active_changed, this), midi_ui_context());
_route->DropReferences.connect (route_connections, MISSING_INVALIDATOR, ui_bind (&Strip::notify_route_deleted, this), midi_ui_context());
_route->active_changed.connect (route_connections, invalidator(), ui_bind (&Strip::notify_active_changed, this), ui_context());
_route->DropReferences.connect (route_connections, invalidator(), ui_bind (&Strip::notify_route_deleted, this), ui_context());
// TODO
// SelectedChanged

View File

@ -59,8 +59,15 @@ Surface::Surface (MackieControlProtocol& mcp, jack_client_t* jack, const std::st
DEBUG_TRACE (DEBUG::MackieControl, "Surface::init\n");
MIDI::Manager * mm = MIDI::Manager::instance();
MIDI::Port * input = mm->add_port (new MIDI::Port (string_compose (_("%1 in"), device_name), MIDI::Port::IsInput, jack));
MIDI::Port * output = mm->add_port (new MIDI::Port (string_compose (_("%1 out"), device_name), MIDI::Port::IsOutput, jack));
MIDI::Port * input = new MIDI::Port (string_compose (_("%1 in"), device_name), MIDI::Port::IsInput, jack);
MIDI::Port * output =new MIDI::Port (string_compose (_("%1 out"), device_name), MIDI::Port::IsOutput, jack);
input->set_centrally_parsed (false);
output->set_centrally_parsed (false);
mm->add_port (input);
mm->add_port (output);
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("surface has ports named %1 and %2\n",
input->name(), output->name()));