summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2015-10-07 13:17:42 -0400
committerPaul Davis <paul@linuxaudiosystems.com>2015-10-07 13:17:49 -0400
commitce9b271a92c8c78c3eace6a0da3438ecdae57107 (patch)
tree6e13a5b2ba6f4abd41fdda22f5b263d222053d60
parent7675739f4509e60f8519b4acb3998617d7e5e08d (diff)
track Mackie MIDI port connection status as primary trigger for handshake with device
-rw-r--r--libs/surfaces/mackie/gui.cc2
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.cc56
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.h2
-rw-r--r--libs/surfaces/mackie/surface.cc77
-rw-r--r--libs/surfaces/mackie/surface.h16
-rw-r--r--libs/surfaces/mackie/surface_port.cc12
-rw-r--r--libs/surfaces/mackie/surface_port.h61
7 files changed, 161 insertions, 65 deletions
diff --git a/libs/surfaces/mackie/gui.cc b/libs/surfaces/mackie/gui.cc
index 156070dbc8..a4907fe7a3 100644
--- a/libs/surfaces/mackie/gui.cc
+++ b/libs/surfaces/mackie/gui.cc
@@ -664,7 +664,7 @@ void
MackieControlProtocolGUI::discover_clicked ()
{
/* this should help to get things started */
- _cp.midi_connectivity_established ();
+ _cp.ping_devices ();
}
void
diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc
index b1a7e2a976..b20cbfa1d9 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol.cc
@@ -87,9 +87,9 @@ const int MackieControlProtocol::MODIFIER_CMDALT = 0x8;
const int MackieControlProtocol::MODIFIER_ZOOM = 0x10;
const int MackieControlProtocol::MODIFIER_SCRUB = 0x20;
const int MackieControlProtocol::MAIN_MODIFIER_MASK = (MackieControlProtocol::MODIFIER_OPTION|
- MackieControlProtocol::MODIFIER_CONTROL|
- MackieControlProtocol::MODIFIER_SHIFT|
- MackieControlProtocol::MODIFIER_CMDALT);
+ MackieControlProtocol::MODIFIER_CONTROL|
+ MackieControlProtocol::MODIFIER_SHIFT|
+ MackieControlProtocol::MODIFIER_CMDALT);
MackieControlProtocol* MackieControlProtocol::_instance = 0;
@@ -184,16 +184,14 @@ MackieControlProtocol::thread_init ()
}
void
-MackieControlProtocol::midi_connectivity_established ()
+MackieControlProtocol::ping_devices ()
{
- for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
- (*si)->say_hello ();
- }
+ /* should not be called if surfaces are not connected, but will not
+ * malfunction if it is.
+ */
- if (_device_info.no_handshake()) {
- for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
- (*si)->turn_it_on ();
- }
+ for (Surfaces::const_iterator si = surfaces.begin(); si != surfaces.end(); ++si) {
+ (*si)->connected ();
}
}
@@ -725,7 +723,7 @@ gboolean
ArdourSurface::ipmidi_input_handler (GIOChannel*, GIOCondition condition, void *data)
{
ArdourSurface::MackieControlProtocol::ipMIDIHandler* ipm = static_cast<ArdourSurface::MackieControlProtocol::ipMIDIHandler*>(data);
- return ipm->mcp->midi_input_handler (Glib::IOCondition (condition), ipm->port);
+ return ipm->mcp->midi_input_handler (Glib::IOCondition (condition), ipm->port);
}
int
@@ -822,24 +820,24 @@ MackieControlProtocol::create_surfaces ()
if ((fd = input_port.selectable ()) >= 0) {
- GIOChannel* ioc = g_io_channel_unix_new (fd);
- GSource* gsrc = g_io_create_watch (ioc, GIOCondition (G_IO_IN|G_IO_HUP|G_IO_ERR));
+ GIOChannel* ioc = g_io_channel_unix_new (fd);
+ GSource* gsrc = g_io_create_watch (ioc, GIOCondition (G_IO_IN|G_IO_HUP|G_IO_ERR));
- /* hack up an object so that in the callback from the event loop
- we have both the MackieControlProtocol and the input port.
+ /* hack up an object so that in the callback from the event loop
+ we have both the MackieControlProtocol and the input port.
- If we were using C++ for this stuff we wouldn't need this
- but a nasty, not-fixable bug in the binding between C
- and C++ makes it necessary to avoid C++ for the IO
- callback setup.
- */
+ If we were using C++ for this stuff we wouldn't need this
+ but a nasty, not-fixable bug in the binding between C
+ and C++ makes it necessary to avoid C++ for the IO
+ callback setup.
+ */
- ipMIDIHandler* ipm = new ipMIDIHandler (); /* we will leak this sizeof(pointer)*2 sized object */
- ipm->mcp = this;
- ipm->port = &input_port;
+ ipMIDIHandler* ipm = new ipMIDIHandler (); /* we will leak this sizeof(pointer)*2 sized object */
+ ipm->mcp = this;
+ ipm->port = &input_port;
- g_source_set_callback (gsrc, (GSourceFunc) ipmidi_input_handler, ipm, NULL);
- g_source_attach (gsrc, main_loop()->get_context()->gobj());
+ g_source_set_callback (gsrc, (GSourceFunc) ipmidi_input_handler, ipm, NULL);
+ g_source_attach (gsrc, main_loop()->get_context()->gobj());
}
}
}
@@ -1027,10 +1025,10 @@ MackieControlProtocol::update_timecode_display()
void MackieControlProtocol::notify_parameter_changed (std::string const & p)
{
if (p == "punch-in") {
- // no such button right now
+ // no such button right now
// update_global_button (Button::PunchIn, session->config.get_punch_in());
} else if (p == "punch-out") {
- // no such button right now
+ // no such button right now
// update_global_button (Button::PunchOut, session->config.get_punch_out());
} else if (p == "clicking") {
update_global_button (Button::Click, Config->get_clicking());
@@ -1314,7 +1312,7 @@ MackieControlProtocol::handle_button_event (Surface& surface, Button& button, Bu
if (action.find ('/') != string::npos) { /* good chance that this is really an action */
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Looked up action for button %1 with modifier %2, got [%3]\n",
- button.bid(), _modifier_state, action));
+ button.bid(), _modifier_state, action));
/* if there is a bound action for this button, and this is a press event,
carry out the action. If its a release event, do nothing since we
diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h
index 0536a0c764..93e917b1b5 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.h
+++ b/libs/surfaces/mackie/mackie_control_protocol.h
@@ -220,7 +220,7 @@ class MackieControlProtocol
bool session_load () { return _session_load; }
void not_session_load () { _session_load = false; }
- void midi_connectivity_established ();
+ void ping_devices ();
protected:
// shut down the surface
diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc
index 5bbb081487..65bb25e01c 100644
--- a/libs/surfaces/mackie/surface.cc
+++ b/libs/surfaces/mackie/surface.cc
@@ -25,6 +25,7 @@
#include "midi++/port.h"
+#include "ardour/audioengine.h"
#include "ardour/automation_control.h"
#include "ardour/debug.h"
#include "ardour/route.h"
@@ -88,6 +89,7 @@ Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, ui
, _jog_wheel (0)
, _master_fader (0)
, _last_master_gain_written (-0.0f)
+ , connection_state (0)
{
DEBUG_TRACE (DEBUG::MackieControl, "Surface::Surface init\n");
@@ -120,6 +122,11 @@ Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, ui
DEBUG_TRACE (DEBUG::MackieControl, "init_strips done\n");
}
+ /*
+ */
+
+ ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&Surface::connection_handler, this, _1, _2, _3, _4, _5), &_mcp);
+
connect_to_signals ();
DEBUG_TRACE (DEBUG::MackieControl, "Surface::Surface done\n");
@@ -147,6 +154,60 @@ Surface::~Surface ()
DEBUG_TRACE (DEBUG::MackieControl, "Surface::~Surface done\n");
}
+void
+Surface::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
+{
+ string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->input_name());
+ string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (_port->output_name());
+
+ if (ni == name1 || ni == name2) {
+ if (yn) {
+ connection_state |= InputConnected;
+ } else {
+ connection_state &= ~InputConnected;
+ }
+ } else if (no == name1 || no == name2) {
+ if (yn) {
+ connection_state |= OutputConnected;
+ } else {
+ connection_state &= ~OutputConnected;
+ }
+ }
+
+ if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
+
+ /* this will send a device query message, which should
+ result in a response that will kick off device type
+ discovery and activation of the surface(s).
+
+ The intended order of events is:
+
+ - each surface sends a device query message
+ - devices respond with either MCP or LCP response (sysex in both
+ cases)
+ - sysex message causes Surface::turn_it_on() which tells the
+ MCP object that the surface is ready, and sets up strip
+ displays and binds faders and buttons for that surface
+
+ In the case of LCP, where this is a handshake process that could
+ fail, the response process to the initial sysex after a device query
+ will mark the surface inactive, which won't shut anything down
+ but will stop any writes to the device.
+
+ Note: there are no known cases of the handshake process failing.
+
+ We actually can't initiate this in this callback, so we have
+ to queue it with the MCP event loop.
+ */
+
+ connected ();
+
+ } else {
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 disconnected (input or output or both)\n", _name));
+ _active = false;
+ }
+}
+
XMLNode&
Surface::get_state()
{
@@ -401,7 +462,7 @@ Surface::handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t pb, uin
*/
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface::handle_midi_pitchbend_message on port %3, fader = %1 value = %2 (%4)\n",
- fader_id, pb, _number, pb/16384.0));
+ fader_id, pb, _number, pb/16384.0));
if (_mcp.device_info().no_handshake()) {
turn_it_on ();
@@ -608,7 +669,6 @@ calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iter
return retval;
}
-// not used right now
MidiByteArray
Surface::host_connection_query (MidiByteArray & bytes)
{
@@ -634,7 +694,6 @@ Surface::host_connection_query (MidiByteArray & bytes)
return response;
}
-// not used right now
MidiByteArray
Surface::host_connection_confirmation (const MidiByteArray & bytes)
{
@@ -1102,3 +1161,15 @@ Surface::hui_heartbeat ()
MidiByteArray msg (3, MIDI::on, 0x0, 0x0);
_port->write (msg);
}
+
+void
+Surface::connected ()
+{
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 now connected, trying to ping device...\n", _name));
+
+ say_hello ();
+
+ if (_mcp.device_info().no_handshake()) {
+ turn_it_on ();
+ }
+}
diff --git a/libs/surfaces/mackie/surface.h b/libs/surfaces/mackie/surface.h
index 1c989ec518..1afa1c0de7 100644
--- a/libs/surfaces/mackie/surface.h
+++ b/libs/surfaces/mackie/surface.h
@@ -3,6 +3,7 @@
#include <stdint.h>
+#include "pbd/signals.h"
#include "pbd/xml++.h"
#include "midi++/types.h"
@@ -18,6 +19,7 @@ namespace MIDI {
namespace ARDOUR {
class Route;
+ class Port;
}
class MidiByteArray;
@@ -49,7 +51,7 @@ public:
uint32_t number() const { return _number; }
const std::string& name() { return _name; }
- void say_hello ();
+ void connected ();
bool active() const { return _active; }
@@ -174,15 +176,25 @@ public:
Mackie::JogWheel* _jog_wheel;
Fader* _master_fader;
float _last_master_gain_written;
-
+ PBD::ScopedConnection port_connection;
+
void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count);
MidiByteArray host_connection_query (MidiByteArray& bytes);
MidiByteArray host_connection_confirmation (const MidiByteArray& bytes);
+ void say_hello ();
void init_controls ();
void init_strips (uint32_t n);
void setup_master ();
void master_gain_changed ();
+ void connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool);
+
+ enum ConnectionState {
+ InputConnected = 0x1,
+ OutputConnected = 0x2
+ };
+
+ int connection_state;
};
}
diff --git a/libs/surfaces/mackie/surface_port.cc b/libs/surfaces/mackie/surface_port.cc
index 3129b5a1fd..50bb206cdf 100644
--- a/libs/surfaces/mackie/surface_port.cc
+++ b/libs/surfaces/mackie/surface_port.cc
@@ -144,6 +144,18 @@ SurfacePort::set_state (const XMLNode& node, int version)
return 0;
}
+std::string
+SurfacePort::input_name () const
+{
+ return _async_in->name();
+}
+
+std::string
+SurfacePort::output_name () const
+{
+ return _async_out->name();
+}
+
// wrapper for one day when strerror_r is working properly
string fetch_errmsg (int error_number)
{
diff --git a/libs/surfaces/mackie/surface_port.h b/libs/surfaces/mackie/surface_port.h
index 2c78e692a7..8b052ec65e 100644
--- a/libs/surfaces/mackie/surface_port.h
+++ b/libs/surfaces/mackie/surface_port.h
@@ -1,19 +1,19 @@
/*
- Copyright (C) 2006,2007 John Anderson
+ Copyright (C) 2006,2007 John Anderson
- 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 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.
+ 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.
+ 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 surface_port_h
#define surface_port_h
@@ -47,32 +47,35 @@ namespace Mackie
class Surface;
/**
- Make a relationship between a midi port and a Mackie device.
+ Make a relationship between a midi port and a Mackie device.
*/
class SurfacePort
{
-public:
- SurfacePort (Mackie::Surface&);
- virtual ~SurfacePort();
+ public:
+ SurfacePort (Mackie::Surface&);
+ virtual ~SurfacePort();
- /// an easier way to output bytes via midi
- int write (const MidiByteArray&);
+ /// an easier way to output bytes via midi
+ int write (const MidiByteArray&);
- 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; }
- XMLNode& get_state ();
- int set_state (const XMLNode&, int version);
+ std::string input_name() const;
+ std::string output_name() const;
-protected:
+ XMLNode& get_state ();
+ int set_state (const XMLNode&, int version);
-private:
- Mackie::Surface* _surface;
- MIDI::Port* _input_port;
- MIDI::Port* _output_port;
- boost::shared_ptr<ARDOUR::Port> _async_in;
- boost::shared_ptr<ARDOUR::Port> _async_out;
+ protected:
+
+ private:
+ Mackie::Surface* _surface;
+ MIDI::Port* _input_port;
+ MIDI::Port* _output_port;
+ boost::shared_ptr<ARDOUR::Port> _async_in;
+ boost::shared_ptr<ARDOUR::Port> _async_out;
};
std::ostream& operator << (std::ostream& , const SurfacePort& port);