track Mackie MIDI port connection status as primary trigger for handshake with device
This commit is contained in:
parent
7675739f45
commit
ce9b271a92
|
@ -664,7 +664,7 @@ void
|
|||
MackieControlProtocolGUI::discover_clicked ()
|
||||
{
|
||||
/* this should help to get things started */
|
||||
_cp.midi_connectivity_established ();
|
||||
_cp.ping_devices ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user