summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Davis <paul@linuxaudiosystems.com>2015-11-24 18:00:11 -0500
committerPaul Davis <paul@linuxaudiosystems.com>2015-11-24 18:00:11 -0500
commita15cf9f0b32d45a237bbd12adf0e2b985a817eeb (patch)
tree251f631533a3670daf3bdfd0c23b7f6161a2361c
parent2f1cdd3ffe0c8d1b9498e8edbd950b18e082dd00 (diff)
get faderport i/o working, basics of identifying control activity
-rw-r--r--libs/midi++2/parser.cc2
-rw-r--r--libs/surfaces/faderport/faderport.cc512
-rw-r--r--libs/surfaces/faderport/faderport.h (renamed from libs/surfaces/faderport/faderport_midi_protocol.h)112
-rw-r--r--libs/surfaces/faderport/faderport_interface.cc14
-rw-r--r--libs/surfaces/faderport/faderport_midi_protocol.cc270
-rw-r--r--libs/surfaces/faderport/fmcp_gui.cc16
-rw-r--r--libs/surfaces/faderport/wscript2
7 files changed, 627 insertions, 301 deletions
diff --git a/libs/midi++2/parser.cc b/libs/midi++2/parser.cc
index e11094d26f..fcee844cef 100644
--- a/libs/midi++2/parser.cc
+++ b/libs/midi++2/parser.cc
@@ -174,7 +174,7 @@ Parser::trace_event (Parser &, MIDI::byte *msg, size_t len)
*o << trace_prefix
<< "Channel "
<< (msg[0]&0xF)+1
- << " PolyPressure"
+ << " PolyPressure "
<< (int) msg[1]
<< endmsg;
break;
diff --git a/libs/surfaces/faderport/faderport.cc b/libs/surfaces/faderport/faderport.cc
new file mode 100644
index 0000000000..4cc541bf7b
--- /dev/null
+++ b/libs/surfaces/faderport/faderport.cc
@@ -0,0 +1,512 @@
+/*
+ Copyright (C) 2006 Paul Davis
+
+ 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.
+
+ 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.
+
+*/
+
+#include <stdint.h>
+
+#include <sstream>
+#include <algorithm>
+
+#include <glibmm/fileutils.h>
+#include <glibmm/miscutils.h>
+
+#include "pbd/controllable_descriptor.h"
+#include "pbd/error.h"
+#include "pbd/failed_constructor.h"
+#include "pbd/file_utils.h"
+#include "pbd/xml++.h"
+#include "pbd/compose.h"
+
+#include "midi++/port.h"
+
+#include "ardour/audioengine.h"
+#include "ardour/filesystem_paths.h"
+#include "ardour/session.h"
+#include "ardour/route.h"
+#include "ardour/midi_ui.h"
+#include "ardour/midi_port.h"
+#include "ardour/rc_configuration.h"
+#include "ardour/midiport_manager.h"
+#include "ardour/debug.h"
+#include "ardour/async_midi_port.h"
+
+#include "faderport.h"
+
+using namespace ARDOUR;
+using namespace PBD;
+using namespace Glib;
+using namespace std;
+
+#include "i18n.h"
+
+#define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
+
+FaderPort::FaderPort (Session& s)
+ : ControlProtocol (s, _("Faderport"))
+ , _motorised (true)
+ , _threshold (10)
+ , gui (0)
+ , connection_state (ConnectionState (0))
+ , _device_active (false)
+ , fader_msb (0)
+ , fader_lsb (0)
+{
+ boost::shared_ptr<ARDOUR::Port> inp;
+ boost::shared_ptr<ARDOUR::Port> outp;
+
+ inp = AudioEngine::instance()->register_input_port (DataType::MIDI, "Faderport Recv", true);
+ outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "Faderport Send", true);
+
+ _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(inp);
+ _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(outp);
+
+ if (_input_port == 0 || _output_port == 0) {
+ throw failed_constructor();
+ }
+
+ do_feedback = false;
+ _feedback_interval = 10 * 1000; // microseconds
+ last_feedback_time = 0;
+ native_counter = 0;
+
+ _current_bank = 0;
+ _bank_size = 0;
+
+ /* handle device inquiry response */
+ _input_port->parser()->sysex.connect_same_thread (midi_connections, boost::bind (&FaderPort::sysex_handler, this, _1, _2, _3));
+ /* handle switches */
+ _input_port->parser()->poly_pressure.connect_same_thread (midi_connections, boost::bind (&FaderPort::switch_handler, this, _1, _2));
+ /* handle encoder */
+ _input_port->parser()->pitchbend.connect_same_thread (midi_connections, boost::bind (&FaderPort::encoder_handler, this, _1, _2));
+ /* handle fader */
+ _input_port->parser()->controller.connect_same_thread (midi_connections, boost::bind (&FaderPort::fader_handler, this, _1, _2));
+
+ /* This connection means that whenever data is ready from the input
+ * port, the relevant thread will invoke our ::midi_input_handler()
+ * method, which will read the data, and invoke the parser.
+ */
+
+ _input_port->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &FaderPort::midi_input_handler), _input_port));
+ _input_port->xthread().attach (midi_ui_context()->main_loop()->get_context());
+
+ Session::SendFeedback.connect_same_thread (*this, boost::bind (&FaderPort::send_feedback, this));
+ //Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&FaderPort::send_feedback, this), midi_ui_context());;
+
+ /* this one is cross-thread */
+
+ Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&FaderPort::reset_controllables, this), midi_ui_context());
+
+ /* Catch port connections and disconnections */
+ ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort::connection_handler, this, _1, _2, _3, _4, _5), midi_ui_context());
+
+}
+
+FaderPort::~FaderPort ()
+{
+ if (_input_port) {
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("unregistering input port %1\n", boost::shared_ptr<ARDOUR::Port>(_input_port)->name()));
+ AudioEngine::instance()->unregister_port (_input_port);
+ _input_port.reset ();
+ }
+
+ if (_output_port) {
+// _output_port->drain (10000); //ToDo: is this necessary? It hangs the shutdown, for me
+ DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("unregistering output port %1\n", boost::shared_ptr<ARDOUR::Port>(_output_port)->name()));
+ AudioEngine::instance()->unregister_port (_output_port);
+ _output_port.reset ();
+ }
+
+ tear_down_gui ();
+}
+
+void
+FaderPort::switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
+{
+ switch (tb->controller_number) {
+ case Mute:
+ cerr << "Mute\n";
+ break;
+ case Solo:
+ cerr << "Solo\n";
+ break;
+ case Rec:
+ cerr << "Rec\n";
+ break;
+ case Left:
+ cerr << "Left\n";
+ break;
+ case Bank:
+ cerr << "Bank\n";
+ break;
+ case Right:
+ cerr << "Right\n";
+ break;
+ case Output:
+ cerr << "Output\n";
+ break;
+ case Read:
+ cerr << "Read\n";
+ break;
+ case Write:
+ cerr << "Write\n";
+ break;
+ case Touch:
+ cerr << "Touch\n";
+ break;
+ case Off:
+ cerr << "Off\n";
+ break;
+ case Mix:
+ cerr << "Mix\n";
+ break;
+ case Proj:
+ cerr << "Proj\n";
+ break;
+ case Trns:
+ cerr << "Trns\n";
+ break;
+ case Undo:
+ cerr << "Undo\n";
+ break;
+ case Shift:
+ cerr << "Shift\n";
+ break;
+ case Punch:
+ cerr << "Punch\n";
+ break;
+ case User:
+ cerr << "User\n";
+ break;
+ case Loop:
+ cerr << "Loop\n";
+ break;
+ case Rewind:
+ cerr << "Rewind\n";
+ break;
+ case Ffwd:
+ cerr << "Ffwd\n";
+ break;
+ case Stop:
+ cerr << "Stop\n";
+ break;
+ case Play:
+ cerr << "Play\n";
+ break;
+ case RecEnable:
+ cerr << "RecEnable\n";
+ break;
+ case Fader:
+ cerr << "Fader touch\n";
+ break;
+ default:
+ cerr << "eh?\n";
+ }
+
+ /* send feedback to turn on the LED */
+
+ MIDI::byte buf[3];
+ buf[0] = 0xa0;
+ buf[1] = tb->controller_number;
+ buf[2] = tb->value;
+
+ _output_port->write (buf, 3, 0);
+}
+
+void
+FaderPort::encoder_handler (MIDI::Parser &, MIDI::pitchbend_t pb)
+{
+ if (pb < 8192) {
+ cerr << "Encoder right\n";
+ } else {
+ cerr << "Encoder left\n";
+ }
+}
+
+void
+FaderPort::fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb)
+{
+ bool was_fader = false;
+
+ if (tb->controller_number == 0x0) {
+ fader_msb = tb->value;
+ was_fader = true;
+ } else if (tb->controller_number == 0x20) {
+ fader_lsb = tb->value;
+ was_fader = true;
+ }
+
+ if (was_fader) {
+ cerr << "Fader now at " << ((fader_msb<<7)|fader_lsb) << endl;
+ }
+}
+
+void
+FaderPort::sysex_handler (MIDI::Parser &p, MIDI::byte *buf, size_t sz)
+{
+ if (sz < 17) {
+ return;
+ }
+
+ if (buf[2] == 0x7f &&
+ buf[3] == 0x06 &&
+ buf[4] == 0x02 &&
+ buf[5] == 0x0 &&
+ buf[6] == 0x1 &&
+ buf[7] == 0x06 &&
+ buf[8] == 0x02 &&
+ buf[9] == 0x0 &&
+ buf[10] == 0x01 &&
+ buf[11] == 0x0) {
+ _device_active = true;
+
+ cerr << "FaderPort identified\n";
+
+ /* put it into native mode */
+
+ MIDI::byte native[3];
+ native[0] = 0x91;
+ native[1] = 0x00;
+ native[2] = 0x64;
+
+ _output_port->write (native, 3, 0);
+ }
+}
+
+int
+FaderPort::set_active (bool /*yn*/)
+{
+ return 0;
+}
+
+void
+FaderPort::set_feedback_interval (microseconds_t ms)
+{
+ _feedback_interval = ms;
+}
+
+void
+FaderPort::send_feedback ()
+{
+ /* This is executed in RT "process" context", so no blocking calls
+ */
+
+ if (!do_feedback) {
+ return;
+ }
+
+ microseconds_t now = get_microseconds ();
+
+ if (last_feedback_time != 0) {
+ if ((now - last_feedback_time) < _feedback_interval) {
+ return;
+ }
+ }
+
+ last_feedback_time = now;
+}
+
+bool
+FaderPort::midi_input_handler (Glib::IOCondition ioc, boost::shared_ptr<ARDOUR::AsyncMIDIPort> port)
+{
+ DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", boost::shared_ptr<MIDI::Port>(port)->name()));
+
+ if (ioc & ~IO_IN) {
+ return false;
+ }
+
+ if (ioc & IO_IN) {
+
+ if (port) {
+ port->clear ();
+ }
+
+ DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", boost::shared_ptr<MIDI::Port>(port)->name()));
+ framepos_t now = session->engine().sample_time();
+ port->parse (now);
+ }
+
+ return true;
+}
+
+
+XMLNode&
+FaderPort::get_state ()
+{
+ XMLNode& node (ControlProtocol::get_state());
+
+ XMLNode* child;
+
+ child = new XMLNode (X_("Input"));
+ child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_input_port)->get_state());
+ node.add_child_nocopy (*child);
+
+
+ child = new XMLNode (X_("Output"));
+ child->add_child_nocopy (boost::shared_ptr<ARDOUR::Port>(_output_port)->get_state());
+ node.add_child_nocopy (*child);
+
+ return node;
+}
+
+int
+FaderPort::set_state (const XMLNode& node, int version)
+{
+ XMLNodeList nlist;
+ XMLNodeConstIterator niter;
+ XMLNode const* child;
+
+ if (ControlProtocol::set_state (node, version)) {
+ return -1;
+ }
+
+ if ((child = node.child (X_("Input"))) != 0) {
+ XMLNode* portnode = child->child (Port::state_node_name.c_str());
+ if (portnode) {
+ boost::shared_ptr<ARDOUR::Port>(_input_port)->set_state (*portnode, version);
+ }
+ }
+
+ if ((child = node.child (X_("Output"))) != 0) {
+ XMLNode* portnode = child->child (Port::state_node_name.c_str());
+ if (portnode) {
+ boost::shared_ptr<ARDOUR::Port>(_output_port)->set_state (*portnode, version);
+ }
+ }
+
+ return 0;
+}
+
+int
+FaderPort::set_feedback (bool yn)
+{
+ do_feedback = yn;
+ last_feedback_time = 0;
+ return 0;
+}
+
+bool
+FaderPort::get_feedback () const
+{
+ return do_feedback;
+}
+
+void
+FaderPort::set_current_bank (uint32_t b)
+{
+ _current_bank = b;
+// reset_controllables ();
+}
+
+void
+FaderPort::next_bank ()
+{
+ _current_bank++;
+// reset_controllables ();
+}
+
+void
+FaderPort::prev_bank()
+{
+ if (_current_bank) {
+ _current_bank--;
+// reset_controllables ();
+ }
+}
+
+void
+FaderPort::set_motorised (bool m)
+{
+ _motorised = m;
+}
+
+void
+FaderPort::set_threshold (int t)
+{
+ _threshold = t;
+}
+
+void
+FaderPort::reset_controllables ()
+{
+}
+
+bool
+FaderPort::connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn)
+{
+ if (!_input_port || !_output_port) {
+ return false;
+ }
+
+ string ni = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_input_port)->name());
+ string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_output_port)->name());
+
+ std::cerr << "Checking " << name1 << (yn ? " + " : " - " ) << name2 << " vs. " << ni << " & " << no << std::endl;
+
+ 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;
+ }
+ } else {
+ /* not our ports */
+ return false;
+ }
+
+ if ((connection_state & (InputConnected|OutputConnected)) == (InputConnected|OutputConnected)) {
+
+ /* XXX this is a horrible hack. Without a short sleep here,
+ something prevents the device wakeup messages from being
+ sent and/or the responses from being received.
+ */
+
+ g_usleep (100000);
+ connected ();
+
+ } else {
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("Surface %1 disconnected (input or output or both)\n", _name));
+ _device_active = false;
+ }
+
+ return true; /* connection status changed */
+}
+
+void
+FaderPort::connected ()
+{
+ std::cerr << "faderport connected\n";
+
+ /* send device inquiry */
+
+ MIDI::byte buf[6];
+
+ buf[0] = 0xf0;
+ buf[1] = 0x7e;
+ buf[2] = 0x7f;
+ buf[3] = 0x06;
+ buf[4] = 0x01;
+ buf[5] = 0xf7;
+
+ _output_port->write (buf, 6, 0);
+}
diff --git a/libs/surfaces/faderport/faderport_midi_protocol.h b/libs/surfaces/faderport/faderport.h
index 85dfb9342c..0bf28123b1 100644
--- a/libs/surfaces/faderport/faderport_midi_protocol.h
+++ b/libs/surfaces/faderport/faderport.h
@@ -17,8 +17,8 @@
*/
-#ifndef ardour_generic_midi_control_protocol_h
-#define ardour_generic_midi_control_protocol_h
+#ifndef ardour_surface_faderport_h
+#define ardour_surface_faderport_h
#include <list>
#include <glibmm/threads.h>
@@ -60,13 +60,20 @@ class MIDIControllable;
class MIDIFunction;
class MIDIAction;
-class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
+class FaderPort : public ARDOUR::ControlProtocol {
public:
- FaderportMidiControlProtocol (ARDOUR::Session&);
- virtual ~FaderportMidiControlProtocol();
+ FaderPort (ARDOUR::Session&);
+ virtual ~FaderPort();
int set_active (bool yn);
- static bool probe() { return true; } //do SysEx device check here?
+
+ /* It would be nice to send a device query message here to see if
+ * faderport is out there. But the probe() API doesn't provide
+ * a set of ports to be checked, so there's really no nice
+ * way to do this. We would have to fall back on the PortManager
+ * and get a list of all physical ports. Could be done ....
+ */
+ static bool probe() { return true; }
void set_feedback_interval (ARDOUR::microseconds_t);
@@ -84,6 +91,8 @@ class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
void next_bank ();
void prev_bank ();
+ void reset_controllables ();
+
void set_motorised (bool);
bool motorised () const {
@@ -96,11 +105,11 @@ class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
return _threshold;
}
+ bool device_active() const { return _device_active; }
+
private:
- MIDI::Port* _input_port;
- MIDI::Port* _output_port;
- boost::shared_ptr<ARDOUR::Port> _async_in;
- boost::shared_ptr<ARDOUR::Port> _async_out;
+ boost::shared_ptr<ARDOUR::AsyncMIDIPort> _input_port;
+ boost::shared_ptr<ARDOUR::AsyncMIDIPort> _output_port;
ARDOUR::microseconds_t _feedback_interval;
ARDOUR::microseconds_t last_feedback_time;
@@ -109,10 +118,9 @@ class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
bool do_feedback;
void send_feedback ();
- PBD::ScopedConnection midi_recv_connection;
- void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t);
+ PBD::ScopedConnectionList midi_connections;
- bool midi_input_handler (Glib::IOCondition ioc, ARDOUR::AsyncMIDIPort* port);
+ bool midi_input_handler (Glib::IOCondition ioc, boost::shared_ptr<ARDOUR::AsyncMIDIPort> port);
std::string _current_binding;
uint32_t _bank_size;
@@ -127,6 +135,82 @@ class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
mutable void *gui;
void build_gui ();
+
+ bool connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool yn);
+ PBD::ScopedConnection port_connection;
+
+ enum ConnectionState {
+ InputConnected = 0x1,
+ OutputConnected = 0x2
+ };
+
+ int connection_state;
+ void connected ();
+ bool _device_active;
+ int fader_msb;
+ int fader_lsb;
+
+ void sysex_handler (MIDI::Parser &p, MIDI::byte *, size_t);
+ void switch_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb);
+ void encoder_handler (MIDI::Parser &, MIDI::pitchbend_t pb);
+ void fader_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb);
+
+ enum InButtonID {
+ Mute = 18,
+ Solo = 17,
+ Rec = 16,
+ Left = 19,
+ Bank = 20,
+ Right = 21,
+ Output = 22,
+ Read = 10,
+ Write = 9,
+ Touch = 8,
+ Off = 23,
+ Mix = 11,
+ Proj = 12,
+ Trns = 13,
+ Undo = 14,
+ Shift = 2,
+ Punch = 1,
+ User = 0,
+ Loop = 15,
+ Rewind = 3,
+ Ffwd = 4,
+ Stop = 5,
+ Play = 6,
+ RecEnable = 7,
+ Fader = 127,
+ };
+
+ /*
+ enum OutButtonID {
+ Mute = 18,
+ Solo = 17,
+ Rec = 16,
+ Left = 19,
+ Bank = 20,
+ Right = 21,
+ Output = 22,
+ Read = 10,
+ Write = 9,
+ Touch = 8,
+ Off = 23,
+ Mix = 11,
+ Proj = 12,
+ Trns = 13,
+ Undo = 14,
+ Shift = 2,
+ Punch = 1,
+ User = 0,
+ Loop = 15,
+ Rewind = 3,
+ Ffwd = 4,
+ Stop = 5,
+ Play = 6,
+ RecEnable = 7,
+ }
+ */
};
-#endif /* ardour_generic_midi_control_protocol_h */
+#endif /* ardour_surface_faderport_h */
diff --git a/libs/surfaces/faderport/faderport_interface.cc b/libs/surfaces/faderport/faderport_interface.cc
index c7c2815a15..77809b7dbf 100644
--- a/libs/surfaces/faderport/faderport_interface.cc
+++ b/libs/surfaces/faderport/faderport_interface.cc
@@ -20,27 +20,27 @@
#include <pbd/failed_constructor.h>
#include "control_protocol/control_protocol.h"
-#include "faderport_midi_protocol.h"
+#include "faderport.h"
using namespace ARDOUR;
static ControlProtocol*
new_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/, Session* s)
{
- FaderportMidiControlProtocol* fmcp;
+ FaderPort* fp;
try {
- fmcp = new FaderportMidiControlProtocol (*s);
+ fp = new FaderPort (*s);
} catch (failed_constructor& err) {
return 0;
}
- if (fmcp->set_active (true)) {
- delete fmcp;
+ if (fp->set_active (true)) {
+ delete fp;
return 0;
}
- return fmcp;
+ return fp;
}
static void
@@ -52,7 +52,7 @@ delete_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/, Contr
static bool
probe_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/)
{
- return FaderportMidiControlProtocol::probe ();
+ return FaderPort::probe ();
}
static ControlProtocolDescriptor faderport_midi_descriptor = {
diff --git a/libs/surfaces/faderport/faderport_midi_protocol.cc b/libs/surfaces/faderport/faderport_midi_protocol.cc
deleted file mode 100644
index 23cfc2e430..0000000000
--- a/libs/surfaces/faderport/faderport_midi_protocol.cc
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- Copyright (C) 2006 Paul Davis
-
- 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.
-
- 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.
-
-*/
-
-#include <stdint.h>
-
-#include <sstream>
-#include <algorithm>
-
-#include <glibmm/fileutils.h>
-#include <glibmm/miscutils.h>
-
-#include "pbd/controllable_descriptor.h"
-#include "pbd/error.h"
-#include "pbd/failed_constructor.h"
-#include "pbd/file_utils.h"
-#include "pbd/xml++.h"
-#include "pbd/compose.h"
-
-#include "midi++/port.h"
-
-#include "ardour/audioengine.h"
-#include "ardour/filesystem_paths.h"
-#include "ardour/session.h"
-#include "ardour/route.h"
-#include "ardour/midi_ui.h"
-#include "ardour/midi_port.h"
-#include "ardour/rc_configuration.h"
-#include "ardour/midiport_manager.h"
-#include "ardour/debug.h"
-#include "ardour/async_midi_port.h"
-
-#include "faderport_midi_protocol.h"
-
-using namespace ARDOUR;
-using namespace PBD;
-using namespace Glib;
-using namespace std;
-
-#include "i18n.h"
-
-#define midi_ui_context() MidiControlUI::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
-
-FaderportMidiControlProtocol::FaderportMidiControlProtocol (Session& s)
- : ControlProtocol (s, _("Faderport"))
- , _motorised (true)
- , _threshold (10)
- , gui (0)
-{
- _async_in = AudioEngine::instance()->register_input_port (DataType::MIDI, "Faderport Recv", true);
- _async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, "Faderport Send", true);
-
- if (_async_in == 0 || _async_out == 0) {
- throw failed_constructor();
- }
-
- _input_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_in).get();
- _output_port = boost::dynamic_pointer_cast<AsyncMIDIPort>(_async_out).get();
-
- do_feedback = false;
- _feedback_interval = 10 * 1000; // microseconds
- last_feedback_time = 0;
- native_counter = 0;
-
- _current_bank = 0;
- _bank_size = 0;
-
-//NOTE TO PAUL:
-// "midi_receiver" and "midi_input_handler"
-// were 2 different approaches to try to capture MIDI data; neither seems to work as expected.
-
-
-//not sure if this should do anything
- (*_input_port).parser()->any.connect_same_thread (midi_recv_connection, boost::bind (&FaderportMidiControlProtocol::midi_receiver, this, _1, _2, _3));
-
-//this is raw port acces (?)
-// _input_port->xthread().set_receive_handler (sigc::bind (sigc::mem_fun (this, &FaderportMidiControlProtocol::midi_input_handler), _input_port));
-
- Session::SendFeedback.connect_same_thread (*this, boost::bind (&FaderportMidiControlProtocol::send_feedback, this));
- //Session::SendFeedback.connect (*this, MISSING_INVALIDATOR, boost::bind (&FaderportMidiControlProtocol::send_feedback, this), midi_ui_context());;
-
- /* this one is cross-thread */
-
- //Route::RemoteControlIDChange.connect (*this, MISSING_INVALIDATOR, boost::bind (&FaderportMidiControlProtocol::reset_controllables, this), midi_ui_context());
-
-}
-
-FaderportMidiControlProtocol::~FaderportMidiControlProtocol ()
-{
- if (_input_port) {
- DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("unregistering input port %1\n", _async_in->name()));
- AudioEngine::instance()->unregister_port (_async_in);
- _async_in.reset ((ARDOUR::Port*) 0);
- }
-
- if (_output_port) {
-// _output_port->drain (10000); //ToDo: is this necessary? It hangs the shutdown, for me
- DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("unregistering output port %1\n", _async_out->name()));
- AudioEngine::instance()->unregister_port (_async_out);
- _async_out.reset ((ARDOUR::Port*) 0);
- }
-
- tear_down_gui ();
-}
-
-void
-FaderportMidiControlProtocol::midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t)
-{
-//NOTE: this never did anything
-// printf("got some midi\n");
-}
-
-
-int
-FaderportMidiControlProtocol::set_active (bool /*yn*/)
-{
- return 0;
-}
-
-void
-FaderportMidiControlProtocol::set_feedback_interval (microseconds_t ms)
-{
- _feedback_interval = ms;
-}
-
-void
-FaderportMidiControlProtocol::send_feedback ()
-{
- /* This is executed in RT "process" context", so no blocking calls
- */
-
- if (!do_feedback) {
- return;
- }
-
- microseconds_t now = get_microseconds ();
-
- if (last_feedback_time != 0) {
- if ((now - last_feedback_time) < _feedback_interval) {
- return;
- }
- }
-
- //occasionally tell the Faderport to go into "Native" mode
- //ToDo: trigger this on MIDI port connection ?
- native_counter++;
- if (native_counter > 10) {
- native_counter = 0;
- MIDI::byte midibuf[64];
- MIDI::byte *buf = midibuf;
- *buf++ = (0x91);
- *buf++ = (0x00);
- *buf++ = (0x64);
- _output_port->write (buf, 3, 0);
- }
-
- last_feedback_time = now;
-}
-
-bool
-FaderportMidiControlProtocol::midi_input_handler (Glib::IOCondition ioc, ARDOUR::AsyncMIDIPort* port)
-{
- DEBUG_TRACE (DEBUG::MidiIO, string_compose ("something happend on %1\n", ((ARDOUR::Port*)port)->name()));
-
- if (ioc & ~IO_IN) {
- return false;
- }
-
- if (ioc & IO_IN) {
-
- AsyncMIDIPort* asp = dynamic_cast<AsyncMIDIPort*> (port);
- if (asp) {
- asp->clear ();
- }
-
- DEBUG_TRACE (DEBUG::MidiIO, string_compose ("data available on %1\n", ((ARDOUR::Port*)port)->name()));
-// framepos_t now = _session.engine().sample_time();
-// port->parse (now);
- }
-
- return true;
-}
-
-
-XMLNode&
-FaderportMidiControlProtocol::get_state ()
-{
- XMLNode& node (ControlProtocol::get_state());
- char buf[32];
-
- return node;
-}
-
-int
-FaderportMidiControlProtocol::set_state (const XMLNode& node, int version)
-{
- XMLNodeList nlist;
- XMLNodeConstIterator niter;
- const XMLProperty* prop;
-
- if (ControlProtocol::set_state (node, version)) {
- return -1;
- }
-
- return 0;
-}
-
-int
-FaderportMidiControlProtocol::set_feedback (bool yn)
-{
- do_feedback = yn;
- last_feedback_time = 0;
- return 0;
-}
-
-bool
-FaderportMidiControlProtocol::get_feedback () const
-{
- return do_feedback;
-}
-
-void
-FaderportMidiControlProtocol::set_current_bank (uint32_t b)
-{
- _current_bank = b;
-// reset_controllables ();
-}
-
-void
-FaderportMidiControlProtocol::next_bank ()
-{
- _current_bank++;
-// reset_controllables ();
-}
-
-void
-FaderportMidiControlProtocol::prev_bank()
-{
- if (_current_bank) {
- _current_bank--;
-// reset_controllables ();
- }
-}
-
-void
-FaderportMidiControlProtocol::set_motorised (bool m)
-{
- _motorised = m;
-}
-
-void
-FaderportMidiControlProtocol::set_threshold (int t)
-{
- _threshold = t;
-}
diff --git a/libs/surfaces/faderport/fmcp_gui.cc b/libs/surfaces/faderport/fmcp_gui.cc
index 1569b88d01..46239af57c 100644
--- a/libs/surfaces/faderport/fmcp_gui.cc
+++ b/libs/surfaces/faderport/fmcp_gui.cc
@@ -31,18 +31,18 @@
#include "gtkmm2ext/gtk_ui.h"
#include "gtkmm2ext/utils.h"
-#include "faderport_midi_protocol.h"
+#include "faderport.h"
#include "i18n.h"
class GMCPGUI : public Gtk::VBox
{
public:
- GMCPGUI (FaderportMidiControlProtocol&);
+ GMCPGUI (FaderPort&);
~GMCPGUI ();
private:
- FaderportMidiControlProtocol& cp;
+ FaderPort& cp;
Gtk::ComboBoxText map_combo;
Gtk::Adjustment bank_adjustment;
Gtk::SpinButton bank_spinner;
@@ -63,17 +63,17 @@ using namespace Gtk;
using namespace Gtkmm2ext;
void*
-FaderportMidiControlProtocol::get_gui () const
+FaderPort::get_gui () const
{
if (!gui) {
- const_cast<FaderportMidiControlProtocol*>(this)->build_gui ();
+ const_cast<FaderPort*>(this)->build_gui ();
}
static_cast<Gtk::VBox*>(gui)->show_all();
return gui;
}
void
-FaderportMidiControlProtocol::tear_down_gui ()
+FaderPort::tear_down_gui ()
{
if (gui) {
Gtk::Widget *w = static_cast<Gtk::VBox*>(gui)->get_parent();
@@ -87,14 +87,14 @@ FaderportMidiControlProtocol::tear_down_gui ()
}
void
-FaderportMidiControlProtocol::build_gui ()
+FaderPort::build_gui ()
{
gui = (void*) new GMCPGUI (*this);
}
/*--------------------*/
-GMCPGUI::GMCPGUI (FaderportMidiControlProtocol& p)
+GMCPGUI::GMCPGUI (FaderPort& p)
: cp (p)
, bank_adjustment (1, 1, 100, 1, 10)
, bank_spinner (bank_adjustment)
diff --git a/libs/surfaces/faderport/wscript b/libs/surfaces/faderport/wscript
index e3efc70ed5..73f4504d2b 100644
--- a/libs/surfaces/faderport/wscript
+++ b/libs/surfaces/faderport/wscript
@@ -15,7 +15,7 @@ def configure(conf):
def build(bld):
obj = bld(features = 'cxx cxxshlib')
obj.source = '''
- faderport_midi_protocol.cc
+ faderport.cc
fmcp_gui.cc
faderport_interface.cc
'''