summaryrefslogtreecommitdiff
path: root/libs/surfaces
diff options
context:
space:
mode:
authorBen Loftis <ben@harrisonconsoles.com>2015-11-24 14:17:25 -0600
committerBen Loftis <ben@harrisonconsoles.com>2015-11-24 14:18:14 -0600
commit2f1cdd3ffe0c8d1b9498e8edbd950b18e082dd00 (patch)
tree9363c035232f5fb7babc2b29db988afcb333bfc3 /libs/surfaces
parentbfe92c5b4fbc2bb263636098d45b41e3d4e38c6f (diff)
rough-in for faderport protocol backend
Diffstat (limited to 'libs/surfaces')
-rw-r--r--libs/surfaces/faderport/faderport_interface.cc71
-rw-r--r--libs/surfaces/faderport/faderport_midi_protocol.cc270
-rw-r--r--libs/surfaces/faderport/faderport_midi_protocol.h132
-rw-r--r--libs/surfaces/faderport/fmcp_gui.cc133
-rw-r--r--libs/surfaces/faderport/i18n.h16
-rw-r--r--libs/surfaces/faderport/wscript33
-rw-r--r--libs/surfaces/wscript2
7 files changed, 657 insertions, 0 deletions
diff --git a/libs/surfaces/faderport/faderport_interface.cc b/libs/surfaces/faderport/faderport_interface.cc
new file mode 100644
index 0000000000..c7c2815a15
--- /dev/null
+++ b/libs/surfaces/faderport/faderport_interface.cc
@@ -0,0 +1,71 @@
+/*
+ Copyright (C) 2012 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 <pbd/failed_constructor.h>
+
+#include "control_protocol/control_protocol.h"
+#include "faderport_midi_protocol.h"
+
+using namespace ARDOUR;
+
+static ControlProtocol*
+new_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/, Session* s)
+{
+ FaderportMidiControlProtocol* fmcp;
+
+ try {
+ fmcp = new FaderportMidiControlProtocol (*s);
+ } catch (failed_constructor& err) {
+ return 0;
+ }
+
+ if (fmcp->set_active (true)) {
+ delete fmcp;
+ return 0;
+ }
+
+ return fmcp;
+}
+
+static void
+delete_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/, ControlProtocol* cp)
+{
+ delete cp;
+}
+
+static bool
+probe_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/)
+{
+ return FaderportMidiControlProtocol::probe ();
+}
+
+static ControlProtocolDescriptor faderport_midi_descriptor = {
+ /*name : */ "Faderport",
+ /*id : */ "uri://ardour.org/surfaces/faderport:0",
+ /*ptr : */ 0,
+ /*module : */ 0,
+ /*mandatory : */ 0,
+ /*supports_feedback : */ true,
+ /*probe : */ probe_faderport_midi_protocol,
+ /*initialize : */ new_faderport_midi_protocol,
+ /*destroy : */ delete_faderport_midi_protocol
+};
+
+extern "C" ARDOURSURFACE_API ControlProtocolDescriptor* protocol_descriptor () { printf("HERE ********************************\n"); return &faderport_midi_descriptor; }
+
diff --git a/libs/surfaces/faderport/faderport_midi_protocol.cc b/libs/surfaces/faderport/faderport_midi_protocol.cc
new file mode 100644
index 0000000000..23cfc2e430
--- /dev/null
+++ b/libs/surfaces/faderport/faderport_midi_protocol.cc
@@ -0,0 +1,270 @@
+/*
+ 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/faderport_midi_protocol.h b/libs/surfaces/faderport/faderport_midi_protocol.h
new file mode 100644
index 0000000000..85dfb9342c
--- /dev/null
+++ b/libs/surfaces/faderport/faderport_midi_protocol.h
@@ -0,0 +1,132 @@
+/*
+ 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.
+
+*/
+
+#ifndef ardour_generic_midi_control_protocol_h
+#define ardour_generic_midi_control_protocol_h
+
+#include <list>
+#include <glibmm/threads.h>
+
+#include "ardour/types.h"
+
+#include "control_protocol/control_protocol.h"
+
+namespace PBD {
+ class Controllable;
+ class ControllableDescriptor;
+}
+
+#include <midi++/types.h>
+
+//#include "pbd/signals.h"
+
+
+//#include "midi_byte_array.h"
+#include "types.h"
+
+#include "glibmm/main.h"
+
+namespace MIDI {
+ class Parser;
+ class Port;
+}
+
+
+namespace ARDOUR {
+ class AsyncMIDIPort;
+ class Port;
+ class Session;
+ class MidiPort;
+}
+
+
+class MIDIControllable;
+class MIDIFunction;
+class MIDIAction;
+
+class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
+ public:
+ FaderportMidiControlProtocol (ARDOUR::Session&);
+ virtual ~FaderportMidiControlProtocol();
+
+ int set_active (bool yn);
+ static bool probe() { return true; } //do SysEx device check here?
+
+ void set_feedback_interval (ARDOUR::microseconds_t);
+
+ int set_feedback (bool yn);
+ bool get_feedback () const;
+
+ XMLNode& get_state ();
+ int set_state (const XMLNode&, int version);
+
+ bool has_editor () const { return true; }
+ void* get_gui () const;
+ void tear_down_gui ();
+
+ void set_current_bank (uint32_t);
+ void next_bank ();
+ void prev_bank ();
+
+ void set_motorised (bool);
+
+ bool motorised () const {
+ return _motorised;
+ }
+
+ void set_threshold (int);
+
+ int threshold () const {
+ return _threshold;
+ }
+
+ private:
+ MIDI::Port* _input_port;
+ MIDI::Port* _output_port;
+ boost::shared_ptr<ARDOUR::Port> _async_in;
+ boost::shared_ptr<ARDOUR::Port> _async_out;
+
+ ARDOUR::microseconds_t _feedback_interval;
+ ARDOUR::microseconds_t last_feedback_time;
+ int native_counter;
+
+ bool do_feedback;
+ void send_feedback ();
+
+ PBD::ScopedConnection midi_recv_connection;
+ void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t);
+
+ bool midi_input_handler (Glib::IOCondition ioc, ARDOUR::AsyncMIDIPort* port);
+
+ std::string _current_binding;
+ uint32_t _bank_size;
+ uint32_t _current_bank;
+ /** true if this surface is motorised. If it is, we assume
+ that the surface's controls are never out of sync with
+ Ardour's state, so we don't have to take steps to avoid
+ values jumping around when things are not in sync.
+ */
+ bool _motorised;
+ int _threshold;
+
+ mutable void *gui;
+ void build_gui ();
+};
+
+#endif /* ardour_generic_midi_control_protocol_h */
diff --git a/libs/surfaces/faderport/fmcp_gui.cc b/libs/surfaces/faderport/fmcp_gui.cc
new file mode 100644
index 0000000000..1569b88d01
--- /dev/null
+++ b/libs/surfaces/faderport/fmcp_gui.cc
@@ -0,0 +1,133 @@
+/*
+ Copyright (C) 2009-2012 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 <iostream>
+#include <list>
+#include <string>
+
+#include <gtkmm/comboboxtext.h>
+#include <gtkmm/label.h>
+#include <gtkmm/box.h>
+#include <gtkmm/adjustment.h>
+#include <gtkmm/spinbutton.h>
+#include <gtkmm/table.h>
+
+#include "gtkmm2ext/gtk_ui.h"
+#include "gtkmm2ext/utils.h"
+
+#include "faderport_midi_protocol.h"
+
+#include "i18n.h"
+
+class GMCPGUI : public Gtk::VBox
+{
+public:
+ GMCPGUI (FaderportMidiControlProtocol&);
+ ~GMCPGUI ();
+
+private:
+ FaderportMidiControlProtocol& cp;
+ Gtk::ComboBoxText map_combo;
+ Gtk::Adjustment bank_adjustment;
+ Gtk::SpinButton bank_spinner;
+ Gtk::CheckButton motorised_button;
+ Gtk::Adjustment threshold_adjustment;
+ Gtk::SpinButton threshold_spinner;
+
+ void binding_changed ();
+ void bank_changed ();
+ void motorised_changed ();
+ void threshold_changed ();
+};
+
+using namespace PBD;
+using namespace ARDOUR;
+using namespace std;
+using namespace Gtk;
+using namespace Gtkmm2ext;
+
+void*
+FaderportMidiControlProtocol::get_gui () const
+{
+ if (!gui) {
+ const_cast<FaderportMidiControlProtocol*>(this)->build_gui ();
+ }
+ static_cast<Gtk::VBox*>(gui)->show_all();
+ return gui;
+}
+
+void
+FaderportMidiControlProtocol::tear_down_gui ()
+{
+ if (gui) {
+ Gtk::Widget *w = static_cast<Gtk::VBox*>(gui)->get_parent();
+ if (w) {
+ w->hide();
+ delete w;
+ }
+ }
+ delete (GMCPGUI*) gui;
+ gui = 0;
+}
+
+void
+FaderportMidiControlProtocol::build_gui ()
+{
+ gui = (void*) new GMCPGUI (*this);
+}
+
+/*--------------------*/
+
+GMCPGUI::GMCPGUI (FaderportMidiControlProtocol& p)
+ : cp (p)
+ , bank_adjustment (1, 1, 100, 1, 10)
+ , bank_spinner (bank_adjustment)
+ , motorised_button ("Motorised")
+ , threshold_adjustment (p.threshold(), 1, 127, 1, 10)
+ , threshold_spinner (threshold_adjustment)
+{
+}
+
+GMCPGUI::~GMCPGUI ()
+{
+}
+
+void
+GMCPGUI::bank_changed ()
+{
+// int new_bank = bank_adjustment.get_value() - 1;
+// cp.set_current_bank (new_bank);
+}
+
+void
+GMCPGUI::binding_changed ()
+{
+}
+
+void
+GMCPGUI::motorised_changed ()
+{
+// cp.set_motorised (motorised_button.get_active ());
+}
+
+void
+GMCPGUI::threshold_changed ()
+{
+// cp.set_threshold (threshold_adjustment.get_value());
+}
diff --git a/libs/surfaces/faderport/i18n.h b/libs/surfaces/faderport/i18n.h
new file mode 100644
index 0000000000..dcbbfcf52e
--- /dev/null
+++ b/libs/surfaces/faderport/i18n.h
@@ -0,0 +1,16 @@
+#ifndef __i18n_h__
+#define __i18n_h__
+
+#include "pbd/compose.h"
+#include "pbd/convert.h"
+#include "gettext.h"
+
+#include <vector>
+#include <string>
+
+#define _(Text) dgettext (PACKAGE,Text)
+#define N_(Text) gettext_noop (Text)
+#define X_(Text) Text
+#define I18N(Array) PBD::internationalize (PACKAGE, Array)
+
+#endif // __i18n_h__
diff --git a/libs/surfaces/faderport/wscript b/libs/surfaces/faderport/wscript
new file mode 100644
index 0000000000..e3efc70ed5
--- /dev/null
+++ b/libs/surfaces/faderport/wscript
@@ -0,0 +1,33 @@
+#!/usr/bin/env python
+from waflib.extras import autowaf as autowaf
+import os
+
+# Mandatory variables
+top = '.'
+out = 'build'
+
+def options(opt):
+ autowaf.set_options(opt)
+
+def configure(conf):
+ autowaf.configure(conf)
+
+def build(bld):
+ obj = bld(features = 'cxx cxxshlib')
+ obj.source = '''
+ faderport_midi_protocol.cc
+ fmcp_gui.cc
+ faderport_interface.cc
+ '''
+ obj.export_includes = ['.']
+ obj.defines = [ 'PACKAGE="ardour_faderport"' ]
+ obj.defines += [ 'ARDOURSURFACE_DLL_EXPORTS' ]
+ obj.includes = [ '.', './faderport']
+ obj.name = 'libardour_faderport'
+ obj.target = 'ardour_faderport'
+ obj.uselib = 'GTKMM GTK GDK'
+ obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
+ obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
+
+def shutdown():
+ autowaf.shutdown()
diff --git a/libs/surfaces/wscript b/libs/surfaces/wscript
index 71bb35d6cc..5ab05cfb23 100644
--- a/libs/surfaces/wscript
+++ b/libs/surfaces/wscript
@@ -21,6 +21,7 @@ out = 'build'
children = [
'control_protocol',
+ 'faderport',
'generic_midi',
'mackie',
]
@@ -67,6 +68,7 @@ def configure(conf):
def build(bld):
bld.recurse('control_protocol')
bld.recurse('generic_midi')
+ bld.recurse('faderport')
bld.recurse('mackie')
if bld.is_defined ('HAVE_LO'):