summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2012-04-12 16:41:07 +0000
committerPaul Davis <paul@linuxaudiosystems.com>2012-04-12 16:41:07 +0000
commit0c4fe26b4111e5c7955380d9a7ab55c4c775d6d0 (patch)
tree873e07f1ef5fe386bbebf1cdb259793ca2d62913
parent62620122a96af73c9714c4de492c43382c5f0297 (diff)
MCP: switch devices on the fly; name MIDI ports appropriately; fix active state; move sysex parsing into Surface
git-svn-id: svn://localhost/ardour2/branches/3.0@11942 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--libs/surfaces/mackie/device_info.cc62
-rw-r--r--libs/surfaces/mackie/device_info.h5
-rw-r--r--libs/surfaces/mackie/gui.cc31
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.cc53
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.h2
-rw-r--r--libs/surfaces/mackie/surface.cc153
-rw-r--r--libs/surfaces/mackie/surface.h23
-rw-r--r--libs/surfaces/mackie/surface_port.cc200
-rw-r--r--libs/surfaces/mackie/surface_port.h23
-rw-r--r--mcp_devices/mcpro.xml1
10 files changed, 268 insertions, 285 deletions
diff --git a/libs/surfaces/mackie/device_info.cc b/libs/surfaces/mackie/device_info.cc
index 446f5dd34d..566a01be9a 100644
--- a/libs/surfaces/mackie/device_info.cc
+++ b/libs/surfaces/mackie/device_info.cc
@@ -58,45 +58,61 @@ DeviceInfo::set_state (const XMLNode& node, int /* version */)
{
const XMLProperty* prop;
const XMLNode* child;
-
+
+ if (node.name() != "MackieProtocolDevice") {
+ return -1;
+ }
+
+ /* name is mandatory */
+
+ if ((child = node.child ("Name")) != 0) {
+ if ((prop = child->property ("value")) != 0) {
+ _name = prop->value();
+ } else {
+ return -1;
+ }
+ }
+
if ((child = node.child ("Strips")) != 0) {
- if ((prop = node.property ("value")) != 0) {
+ if ((prop = child->property ("value")) != 0) {
if ((_strip_cnt = atoi (prop->value())) == 0) {
_strip_cnt = 8;
}
}
}
+ if ((child = node.child ("Extenders")) != 0) {
+ if ((prop = child->property ("value")) != 0) {
+ if ((_extenders = atoi (prop->value())) == 0) {
+ _extenders = 0;
+ }
+ }
+ }
+
if ((child = node.child ("TwoCharacterDisplay")) != 0) {
- if ((prop = node.property ("value")) != 0) {
+ if ((prop = child->property ("value")) != 0) {
_has_two_character_display = string_is_affirmative (prop->value());
}
}
if ((child = node.child ("MasterFader")) != 0) {
- if ((prop = node.property ("value")) != 0) {
+ if ((prop = child->property ("value")) != 0) {
_has_master_fader = string_is_affirmative (prop->value());
}
}
if ((child = node.child ("DisplaySegments")) != 0) {
- if ((prop = node.property ("value")) != 0) {
+ if ((prop = child->property ("value")) != 0) {
_has_segmented_display = string_is_affirmative (prop->value());
}
}
if ((child = node.child ("TimecodeDisplay")) != 0) {
- if ((prop = node.property ("value")) != 0) {
+ if ((prop = child->property ("value")) != 0) {
_has_timecode_display = string_is_affirmative (prop->value());
}
}
- if ((child = node.child ("Name")) != 0) {
- if ((prop = node.property ("value")) != 0) {
- _name = prop->value();
- }
- }
-
return 0;
}
@@ -112,6 +128,12 @@ DeviceInfo::strip_cnt() const
return _strip_cnt;
}
+uint32_t
+DeviceInfo::extenders() const
+{
+ return _extenders;
+}
+
bool
DeviceInfo::has_master_fader() const
{
@@ -207,6 +229,7 @@ DeviceInfo::reload_device_info ()
XMLTree tree;
+
if (!tree.read (fullpath.c_str())) {
continue;
}
@@ -216,11 +239,20 @@ DeviceInfo::reload_device_info ()
continue;
}
- di.set_state (*root, 3000); /* version is ignored for now */
-
- device_info[di.name()] = di;
+ if (di.set_state (*root, 3000) == 0) { /* version is ignored for now */
+ device_info[di.name()] = di;
+ std::cerr << di << '\n';
+ }
}
delete devinfos;
}
+std::ostream& operator<< (std::ostream& os, const Mackie::DeviceInfo& di)
+{
+ os << di.name() << ' '
+ << di.strip_cnt() << ' '
+ << di.extenders() << ' '
+ ;
+ return os;
+}
diff --git a/libs/surfaces/mackie/device_info.h b/libs/surfaces/mackie/device_info.h
index c73837843f..f605237510 100644
--- a/libs/surfaces/mackie/device_info.h
+++ b/libs/surfaces/mackie/device_info.h
@@ -20,6 +20,7 @@
#ifndef __ardour_mackie_control_protocol_device_info_h__
#define __ardour_mackie_control_protocol_device_info_h__
+#include <iostream>
#include <stdint.h>
#include <string>
#include <map>
@@ -37,6 +38,7 @@ class DeviceInfo
int set_state (const XMLNode&, int version);
uint32_t strip_cnt () const;
+ uint32_t extenders() const;
bool has_two_character_display() const;
bool has_master_fader () const;
bool has_segmented_display() const;
@@ -48,6 +50,7 @@ class DeviceInfo
private:
uint32_t _strip_cnt;
+ uint32_t _extenders;
bool _has_two_character_display;
bool _has_master_fader;
bool _has_segmented_display;
@@ -67,4 +70,6 @@ class DeviceProfile
}
+std::ostream& operator<< (std::ostream& os, const Mackie::DeviceInfo& di);
+
#endif /* __ardour_mackie_control_protocol_device_info_h__ */
diff --git a/libs/surfaces/mackie/gui.cc b/libs/surfaces/mackie/gui.cc
index 7f49b3e392..76715a4751 100644
--- a/libs/surfaces/mackie/gui.cc
+++ b/libs/surfaces/mackie/gui.cc
@@ -39,11 +39,9 @@ public:
private:
void surface_combo_changed ();
- void extenders_changed ();
MackieControlProtocol& _cp;
Gtk::ComboBoxText _surface_combo;
- Gtk::SpinButton _extenders;
};
void*
@@ -78,46 +76,27 @@ MackieControlProtocolGUI::MackieControlProtocolGUI (MackieControlProtocol& p)
table->attach (_surface_combo, 1, 2, 0, 1);
vector<string> surfaces;
-
+
for (std::map<std::string,DeviceInfo>::iterator i = DeviceInfo::device_info.begin(); i != DeviceInfo::device_info.end(); ++i) {
+ std::cerr << "Dveice known: " << i->first << endl;
surfaces.push_back (i->first);
}
Gtkmm2ext::set_popdown_strings (_surface_combo, surfaces);
_surface_combo.set_active_text (p.device_info().name());
- _extenders.set_range (0, 8);
- _extenders.set_increments (1, 4);
-
- Gtk::Label* l = manage (new Gtk::Label (_("Extenders:")));
- l->set_alignment (0, 0.5);
- table->attach (*l, 0, 1, 1, 2);
- table->attach (_extenders, 1, 2, 1, 2);
-
pack_start (*table);
- Gtk::Label* cop_out = manage (new Gtk::Label (_("<i>You must restart Ardour for changes\nto these settings to take effect.</i>")));
- cop_out->set_use_markup (true);
- pack_start (*cop_out);
-
set_spacing (4);
+ set_border_width (12);
show_all ();
_surface_combo.signal_changed().connect (sigc::mem_fun (*this, &MackieControlProtocolGUI::surface_combo_changed));
- _extenders.signal_changed().connect (sigc::mem_fun (*this, &MackieControlProtocolGUI::extenders_changed));
}
void
MackieControlProtocolGUI::surface_combo_changed ()
{
- if (_surface_combo.get_active_text() == _("Mackie Control")) {
- ARDOUR::Config->set_mackie_emulation (X_("mcu"));
- } else {
- ARDOUR::Config->set_mackie_emulation (X_("bcf"));
- }
+ _cp.set_device (_surface_combo.get_active_text());
}
-void
-MackieControlProtocolGUI::extenders_changed ()
-{
- ARDOUR::Config->set_mackie_extenders (_extenders.get_value_as_int ());
-}
+
diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc
index c316121dc5..c4a37499eb 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol.cc
@@ -321,7 +321,6 @@ MackieControlProtocol::switch_banks (uint32_t initial, bool force)
for (; r != sorted.end() && added < (*si)->n_strips(); ++r, ++added) {
routes.push_back (*r);
- cerr << "\t\tadded " << (*r)->name() << endl;
}
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("give surface %1 routes\n", routes.size()));
@@ -497,21 +496,40 @@ MackieControlProtocol::connect_session_signals()
}
}
+void
+MackieControlProtocol::set_device (const string& device_name)
+{
+ map<string,DeviceInfo>::iterator d = DeviceInfo::device_info.find (device_name);
+
+ if (d == DeviceInfo::device_info.end()) {
+ return;
+ }
+
+ _device_info = d->second;
+
+ surfaces.clear ();
+ create_surfaces ();
+ switch_banks (0, true);
+}
+
void
MackieControlProtocol::create_surfaces ()
{
- string device_name = "mcu";
+ string device_name = _device_info.name();
surface_type_t stype = mcu;
+ char buf[128];
- DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Create %1 surfaces\n",
- 1 + ARDOUR::Config->get_mackie_extenders()));
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Create %1 surfaces\n", 1 + _device_info.extenders()));
- for (uint32_t n = 0; n < 1 + ARDOUR::Config->get_mackie_extenders(); ++n) {
+ for (uint32_t n = 0; n < 1 + _device_info.extenders(); ++n) {
- boost::shared_ptr<Surface> surface (new Surface (*this, session->engine().jack(), device_name, n, stype));
+ boost::shared_ptr<Surface> surface (new Surface (*this, device_name, n, stype));
surfaces.push_back (surface);
+
+ /* next device will be an extender */
- device_name = "mcu_xt";
+ snprintf (buf, sizeof (buf), "%s XT%d", _device_info.name().c_str(), n+1);
+ device_name = buf;
stype = ext;
_input_bundle->add_channel (
@@ -589,10 +607,6 @@ MackieControlProtocol::set_state (const XMLNode & node, int /*version*/)
int retval = 0;
const XMLProperty* prop;
- if ((prop = node.property (X_("device"))) != 0) {
- load_device_info (prop->value());
- }
-
// fetch current bank
if ((prop = node.property (X_("bank"))) != 0) {
string bank = prop->value();
@@ -620,6 +634,10 @@ MackieControlProtocol::set_state (const XMLNode & node, int /*version*/)
_f_actions[n] = action;
}
+ if ((prop = node.property (X_("device"))) != 0) {
+ set_device (prop->value ());
+ }
+
return retval;
}
@@ -1148,19 +1166,6 @@ MackieControlProtocol::force_special_route_to_strip (boost::shared_ptr<Route> r,
}
void
-MackieControlProtocol::load_device_info (const string& name)
-{
- map<string,DeviceInfo>::iterator i = DeviceInfo::device_info.find (name);
-
- if (i == DeviceInfo::device_info.end()) {
- error << string_compose (_("No device info for Mackie Control device \"%1\" - ignored"), name) << endmsg;
- return;
- }
-
- _device_info = i->second;
-}
-
-void
MackieControlProtocol::gui_track_selection_changed (ARDOUR::RouteNotificationListPtr rl)
{
for (Surfaces::iterator s = surfaces.begin(); s != surfaces.end(); ++s) {
diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h
index 978fa222c3..8fa37831ec 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.h
+++ b/libs/surfaces/mackie/mackie_control_protocol.h
@@ -118,6 +118,7 @@ class MackieControlProtocol
const Mackie::DeviceInfo& device_info() const { return _device_info; }
int set_active (bool yn);
+ void set_device (const std::string&);
FlipMode flip_mode () const { return _flip_mode; }
ViewMode view_mode () const { return _view_mode; }
@@ -269,7 +270,6 @@ class MackieControlProtocol
std::vector<std::string> _f_actions;
ButtonMap button_map;
- void load_device_info (const std::string&);
void create_surfaces ();
void port_connected_or_disconnected (std::string, std::string, bool);
bool control_in_use_timeout (Mackie::Surface*, Mackie::Control *, Mackie::Control *);
diff --git a/libs/surfaces/mackie/surface.cc b/libs/surfaces/mackie/surface.cc
index 55cb573051..b056d7b2ec 100644
--- a/libs/surfaces/mackie/surface.cc
+++ b/libs/surfaces/mackie/surface.cc
@@ -38,11 +38,15 @@ using ARDOUR::Panner;
using ARDOUR::Pannable;
using ARDOUR::PannerShell;
-// The MCU sysex header
-static MidiByteArray mackie_sysex_hdr (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x10);
+// The MCU sysex header.4th byte Will be overwritten
+// when we get an incoming sysex that identifies
+// the device type
+static MidiByteArray mackie_sysex_hdr (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x14);
-// The MCU extender sysex header
-static MidiByteArray mackie_sysex_hdr_xt (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x11);
+// The MCU extender sysex header.4th byte Will be overwritten
+// when we get an incoming sysex that identifies
+// the device type
+static MidiByteArray mackie_sysex_hdr_xt (5, MIDI::sysex, 0x0, 0x0, 0x66, 0x15);
static MidiByteArray empty_midi_byte_array;
@@ -121,33 +125,18 @@ static GlobalControlDefinition mackie_global_controls[] = {
{ "", 0, Button::factory, "" }
};
-Surface::Surface (MackieControlProtocol& mcp, jack_client_t* jack, const std::string& device_name, uint32_t number, surface_type_t stype)
+Surface::Surface (MackieControlProtocol& mcp, const std::string& device_name, uint32_t number, surface_type_t stype)
: _mcp (mcp)
, _stype (stype)
, _number (number)
- , _active (false)
+ , _name (device_name)
+ , _active (true)
, _connected (false)
, _jog_wheel (0)
{
DEBUG_TRACE (DEBUG::MackieControl, "Surface::init\n");
- MIDI::Manager * mm = MIDI::Manager::instance();
-
- 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()));
-
- _port = new SurfacePort (*this, *input, *output);
- _port->open();
- _port->inactive_event.connect_same_thread (*this, boost::bind (&Surface::handle_port_inactive, this, _port));
+ _port = new SurfacePort (*this);
switch (stype) {
case mcu:
@@ -177,7 +166,12 @@ Surface::~Surface ()
{
DEBUG_TRACE (DEBUG::MackieControl, "Surface: destructor\n");
- zero_all ();
+ // faders to minimum
+ write_sysex (0x61);
+ // All LEDs off
+ write_sysex (0x62);
+ // Reset (reboot into offline mode)
+ // _write_sysex (0x63);
// delete groups
for (Groups::iterator it = groups.begin(); it != groups.end(); ++it) {
@@ -307,11 +301,14 @@ Surface::connect_to_signals ()
{
if (!_connected) {
+
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 connecting to signals on port %2\n",
number(), _port->input_port().name()));
MIDI::Parser* p = _port->input_port().parser();
+ /* Incoming sysex */
+ p->sysex.connect_same_thread (*this, boost::bind (&Surface::handle_midi_sysex, this, _1, _2, _3));
/* V-Pot messages are Controller */
p->controller.connect_same_thread (*this, boost::bind (&Surface::handle_midi_controller_message, this, _1, _2));
/* Button messages are NoteOn */
@@ -436,6 +433,113 @@ Surface::handle_midi_controller_message (MIDI::Parser &, MIDI::EventTwoBytes* ev
}
void
+Surface::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
+{
+ MidiByteArray bytes (count, raw_bytes);
+
+
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
+
+ /* always save the device type ID so that our outgoing sysex messages
+ * are correct
+ */
+
+ if (_stype == mcu) {
+ mackie_sysex_hdr[3] = bytes[4];
+ } else {
+ mackie_sysex_hdr_xt[3] = bytes[4];
+ }
+
+ switch (bytes[5]) {
+ case 0x01:
+ /* MCP: Device Ready
+ LCP: Connection Challenge
+ */
+ if (bytes[4] == 0x10 || bytes[4] == 0x11) {
+ write_sysex (host_connection_query (bytes));
+ } else {
+ _active = true;
+ }
+ break;
+
+ case 0x03: /* LCP Connection Confirmation */
+ if (bytes[4] == 0x10 || bytes[4] == 0x11) {
+ write_sysex (host_connection_confirmation (bytes));
+ _active = true;
+ }
+ break;
+
+ case 0x04: /* LCP: Confirmation Denied */
+ _active = false;
+ break;
+ default:
+ error << "MCP: unknown sysex: " << bytes << endmsg;
+ }
+}
+
+static MidiByteArray
+calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
+{
+ MidiByteArray l;
+ back_insert_iterator<MidiByteArray> back (l);
+ copy (begin, end, back);
+
+ MidiByteArray retval;
+
+ // this is how to calculate the response to the challenge.
+ // from the Logic docs.
+ retval << (0x7f & (l[0] + (l[1] ^ 0xa) - l[3]));
+ retval << (0x7f & ( (l[2] >> l[3]) ^ (l[0] + l[3])));
+ retval << (0x7f & ((l[3] - (l[2] << 2)) ^ (l[0] | l[1])));
+ retval << (0x7f & (l[1] - l[2] + (0xf0 ^ (l[3] << 4))));
+
+ return retval;
+}
+
+// not used right now
+MidiByteArray
+Surface::host_connection_query (MidiByteArray & bytes)
+{
+ MidiByteArray response;
+
+ if (bytes[4] != 0x10 && bytes[4] != 0x11) {
+ /* not a Logic Control device - no response required */
+ return response;
+ }
+
+ // handle host connection query
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
+
+ if (bytes.size() != 18) {
+ cerr << "expecting 18 bytes, read " << bytes << " from " << _port->input_port().name() << endl;
+ return response;
+ }
+
+ // build and send host connection reply
+ response << 0x02;
+ copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
+ response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
+ return response;
+}
+
+// not used right now
+MidiByteArray
+Surface::host_connection_confirmation (const MidiByteArray & bytes)
+{
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
+
+ // decode host connection confirmation
+ if (bytes.size() != 14) {
+ ostringstream os;
+ os << "expecting 14 bytes, read " << bytes << " from " << _port->input_port().name();
+ throw MackieControlException (os.str());
+ }
+
+ // send version request
+ return MidiByteArray (2, 0x13, 0x00);
+}
+
+void
Surface::handle_port_inactive (SurfacePort * port)
{
_active = false;
@@ -737,3 +841,4 @@ Surface::gui_selection_changed (ARDOUR::RouteNotificationListPtr routes)
_port->write (msg);
}
+
diff --git a/libs/surfaces/mackie/surface.h b/libs/surfaces/mackie/surface.h
index 310eb00c24..a105125a0c 100644
--- a/libs/surfaces/mackie/surface.h
+++ b/libs/surfaces/mackie/surface.h
@@ -38,13 +38,12 @@ class Led;
class Surface : public PBD::ScopedConnectionList
{
public:
- Surface (MackieControlProtocol&, jack_client_t* jack, const std::string& device_name, uint32_t number, surface_type_t stype);
+ Surface (MackieControlProtocol&, const std::string& name, uint32_t number, surface_type_t stype);
virtual ~Surface();
surface_type_t type() const { return _stype; }
uint32_t number() const { return _number; }
-
- MackieControlProtocol& mcp() const { return _mcp; }
+ const std::string& name() { return _name; }
bool active() const { return _active; }
void drop_routes ();
@@ -148,20 +147,26 @@ public:
void gui_selection_changed (ARDOUR::RouteNotificationListPtr);
+ MackieControlProtocol& mcp() const { return _mcp; }
+
protected:
void init_controls();
void init_strips ();
private:
MackieControlProtocol& _mcp;
- SurfacePort* _port;
- surface_type_t _stype;
- uint32_t _number;
- bool _active;
- bool _connected;
- Mackie::JogWheel* _jog_wheel;
+ SurfacePort* _port;
+ surface_type_t _stype;
+ uint32_t _number;
+ std::string _name;
+ bool _active;
+ bool _connected;
+ Mackie::JogWheel* _jog_wheel;
void jog_wheel_state_display (Mackie::JogWheel::State state);
+ void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count);
+ MidiByteArray host_connection_query (MidiByteArray& bytes);
+ MidiByteArray host_connection_confirmation (const MidiByteArray& bytes);
};
}
diff --git a/libs/surfaces/mackie/surface_port.cc b/libs/surfaces/mackie/surface_port.cc
index d35c15da3f..ebc2ab1117 100644
--- a/libs/surfaces/mackie/surface_port.cc
+++ b/libs/surfaces/mackie/surface_port.cc
@@ -29,9 +29,11 @@
#include "ardour/debug.h"
#include "ardour/rc_configuration.h"
+#include "ardour/session.h"
+#include "ardour/audioengine.h"
#include "controls.h"
-#include "mackie_control_exception.h"
+#include "mackie_control_protocol.h"
#include "surface.h"
#include "surface_port.h"
@@ -42,22 +44,35 @@ using namespace std;
using namespace Mackie;
using namespace PBD;
-/** @param input_port Input MIDI::Port; this object takes responsibility for removing it from
- * the MIDI::Manager and destroying it.
- * @param output_port Output MIDI::Port; responsibility similarly taken.
+/** @param input_port Input MIDI::Port; this object takes responsibility for
+ * adding & removing it from the MIDI::Manager and destroying it. @param
+ * output_port Output MIDI::Port; responsibility similarly taken.
*/
-SurfacePort::SurfacePort (Surface& s, MIDI::Port & input_port, MIDI::Port & output_port)
+SurfacePort::SurfacePort (Surface& s)
: _surface (&s)
- , _input_port (&input_port)
- , _output_port (&output_port)
- , _active (false)
{
+ jack_client_t* jack = MackieControlProtocol::instance()->get_session().engine().jack();
+
+ _input_port = new MIDI::Port (string_compose (_("%1 in"), _surface->name()), MIDI::Port::IsInput, jack);
+ _output_port =new MIDI::Port (string_compose (_("%1 out"), _surface->name()), MIDI::Port::IsOutput, jack);
+
+ /* 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);
}
SurfacePort::~SurfacePort()
{
- close ();
-
MIDI::Manager* mm = MIDI::Manager::instance ();
if (_input_port) {
@@ -78,183 +93,38 @@ string fetch_errmsg (int error_number)
return msg;
}
-MidiByteArray SurfacePort::read()
-{
- const int max_buf_size = 512;
- MIDI::byte buf[max_buf_size];
- MidiByteArray retval;
-
- // check active. Mainly so that the destructor
- // doesn't destroy the mutex while it's still locked
- if (!active()) {
- return retval;
- }
-
- // return nothing read if the lock isn't acquired
-
- // read port and copy to return value
- int nread = input_port().read (buf, sizeof (buf));
-
- if (nread >= 0) {
- retval.copy (nread, buf);
- if ((size_t) nread == sizeof (buf)) {
-#ifdef PORT_DEBUG
- cout << "SurfacePort::read recursive" << endl;
-#endif
- retval << read();
- }
- } else {
- if (errno != EAGAIN) {
- ostringstream os;
- os << "Surface: error reading from port: " << input_port().name();
- os << ": " << errno << fetch_errmsg (errno);
-
- cout << os.str() << endl;
- inactive_event();
- throw MackieControlException (os.str());
- }
- }
-#ifdef PORT_DEBUG
- cout << "SurfacePort::read: " << retval << endl;
-#endif
- return retval;
-}
-
-void SurfacePort::write (const MidiByteArray & mba)
+int
+SurfacePort::write (const MidiByteArray & mba)
{
if (mba.empty()) {
- return;
+ return 0;
}
- if (!active()) return;
-
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("port %1 write %2\n", output_port().name(), mba));
int count = output_port().write (mba.bytes().get(), mba.size(), 0);
if (count != (int)mba.size()) {
+
if (errno == 0) {
+
cout << "port overflow on " << output_port().name() << ". Did not write all of " << mba << endl;
+
} else if (errno != EAGAIN) {
ostringstream os;
os << "Surface: couldn't write to port " << output_port().name();
os << ", error: " << fetch_errmsg (errno) << "(" << errno << ")";
-
cout << os.str() << endl;
- inactive_event();
}
- }
-}
-
-
-void SurfacePort::open()
-{
- DEBUG_TRACE (DEBUG::MackieControl, string_compose ("SurfacePort::open %1\n", *this));
- input_port().parser()->sysex.connect_same_thread (sysex_connection, boost::bind (&SurfacePort::handle_midi_sysex, this, _1, _2, _3));
- _active = true;
-}
-
-void SurfacePort::close()
-{
- DEBUG_TRACE (DEBUG::MackieControl, "SurfacePort::close\n");
- sysex_connection.disconnect();
- if (_surface) {
- // faders to minimum
- _surface->write_sysex (0x61);
- // All LEDs off
- _surface->write_sysex (0x62);
- // Reset (reboot into offline mode)
- _surface->write_sysex (0x63);
+ return -1;
}
- _active = false;
-}
-
-void
-SurfacePort::handle_midi_sysex (MIDI::Parser &, MIDI::byte * raw_bytes, size_t count)
-{
- MidiByteArray bytes (count, raw_bytes);
-
- DEBUG_TRACE (DEBUG::MackieControl, string_compose ("handle_midi_sysex: %1\n", bytes));
-
- switch (bytes[5])
- {
- case 0x01:
- _surface->write_sysex (host_connection_query (bytes));
- break;
- case 0x03:
- // not used right now
- _surface->write_sysex (host_connection_confirmation (bytes));
- break;
- case 0x04:
- inactive_event ();
- cout << "host connection error" << bytes << endl;
- break;
- case 0x14:
- // probe_emulation (bytes);
- break;
- default:
- cout << "unknown sysex: " << bytes << endl;
- }
-}
-
-MidiByteArray calculate_challenge_response (MidiByteArray::iterator begin, MidiByteArray::iterator end)
-{
- MidiByteArray l;
- back_insert_iterator<MidiByteArray> back (l);
- copy (begin, end, back);
-
- MidiByteArray retval;
-
- // this is how to calculate the response to the challenge.
- // from the Logic docs.
- retval << (0x7f & (l[0] + (l[1] ^ 0xa) - l[3]));
- retval << (0x7f & ( (l[2] >> l[3]) ^ (l[0] + l[3])));
- retval << (0x7f & ((l[3] - (l[2] << 2)) ^ (l[0] | l[1])));
- retval << (0x7f & (l[1] - l[2] + (0xf0 ^ (l[3] << 4))));
-
- return retval;
+ return 0;
}
-// not used right now
-MidiByteArray SurfacePort::host_connection_query (MidiByteArray & bytes)
-{
- MidiByteArray response;
-
- // handle host connection query
- DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host connection query: %1\n", bytes));
-
- if (bytes.size() != 18) {
- cerr << "expecting 18 bytes, read " << bytes << " from " << input_port().name() << endl;
- return response;
- }
-
- // build and send host connection reply
- response << 0x02;
- copy (bytes.begin() + 6, bytes.begin() + 6 + 7, back_inserter (response));
- response << calculate_challenge_response (bytes.begin() + 6 + 7, bytes.begin() + 6 + 7 + 4);
- return response;
-}
-
-// not used right now
-MidiByteArray SurfacePort::host_connection_confirmation (const MidiByteArray & bytes)
-{
- DEBUG_TRACE (DEBUG::MackieControl, string_compose ("host_connection_confirmation: %1\n", bytes));
-
- // decode host connection confirmation
- if (bytes.size() != 14) {
- ostringstream os;
- os << "expecting 14 bytes, read " << bytes << " from " << input_port().name();
- throw MackieControlException (os.str());
- }
-
- // send version request
- return MidiByteArray (2, 0x13, 0x00);
-}
-
-
-ostream & Mackie::operator << (ostream & os, const SurfacePort & port)
+ostream &
+Mackie::operator << (ostream & os, const SurfacePort & port)
{
os << "{ ";
os << "name: " << port.input_port().name() << " " << port.output_port().name();
diff --git a/libs/surfaces/mackie/surface_port.h b/libs/surfaces/mackie/surface_port.h
index 8b66073b4a..1a65d8dbcf 100644
--- a/libs/surfaces/mackie/surface_port.h
+++ b/libs/surfaces/mackie/surface_port.h
@@ -44,42 +44,23 @@ class Surface;
class SurfacePort
{
public:
- SurfacePort (Mackie::Surface&, MIDI::Port& input_port, MIDI::Port& output_port);
+ SurfacePort (Mackie::Surface&);
virtual ~SurfacePort();
- void open();
- void close();
-
- /// read bytes from the port. They'll either end up in the
- /// parser, or if that's not active they'll be returned
- MidiByteArray read();
-
/// an easier way to output bytes via midi
- void write (const MidiByteArray&);
+ 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; }
- // emitted when the port goes inactive (ie a read or write failed)
- PBD::Signal0<void> inactive_event;
-
- void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count);
-
- bool active() const { return _active; }
-
protected:
- MidiByteArray host_connection_query (MidiByteArray& bytes);
- MidiByteArray host_connection_confirmation (const MidiByteArray& bytes);
private:
Mackie::Surface* _surface;
MIDI::Port* _input_port;
MIDI::Port* _output_port;
- bool _active;
-
- PBD::ScopedConnection sysex_connection;
};
std::ostream& operator << (std::ostream& , const SurfacePort& port);
diff --git a/mcp_devices/mcpro.xml b/mcp_devices/mcpro.xml
index 54a2f58ac7..6b0c6dfc27 100644
--- a/mcp_devices/mcpro.xml
+++ b/mcp_devices/mcpro.xml
@@ -6,4 +6,5 @@
<SegmentedDisplay value="no"/>
<TimecodeDisplay value="yes"/>
<TwoCharacterDisplay value="yes"/>
+ <Extenders value="0"/>
</MackieProtocolDevice>