mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 23:35:03 +01:00
get faderport i/o working, basics of identifying control activity
This commit is contained in:
parent
2f1cdd3ffe
commit
a15cf9f0b3
7 changed files with 627 additions and 301 deletions
512
libs/surfaces/faderport/faderport.cc
Normal file
512
libs/surfaces/faderport/faderport.cc
Normal file
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
};
|
||||
|
||||
#endif /* ardour_generic_midi_control_protocol_h */
|
||||
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_surface_faderport_h */
|
||||
|
|
@ -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 = {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
'''
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue