mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-11 00:56:33 +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
|
|
@ -174,7 +174,7 @@ Parser::trace_event (Parser &, MIDI::byte *msg, size_t len)
|
||||||
*o << trace_prefix
|
*o << trace_prefix
|
||||||
<< "Channel "
|
<< "Channel "
|
||||||
<< (msg[0]&0xF)+1
|
<< (msg[0]&0xF)+1
|
||||||
<< " PolyPressure"
|
<< " PolyPressure "
|
||||||
<< (int) msg[1]
|
<< (int) msg[1]
|
||||||
<< endmsg;
|
<< endmsg;
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
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
|
#ifndef ardour_surface_faderport_h
|
||||||
#define ardour_generic_midi_control_protocol_h
|
#define ardour_surface_faderport_h
|
||||||
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <glibmm/threads.h>
|
#include <glibmm/threads.h>
|
||||||
|
|
@ -60,13 +60,20 @@ class MIDIControllable;
|
||||||
class MIDIFunction;
|
class MIDIFunction;
|
||||||
class MIDIAction;
|
class MIDIAction;
|
||||||
|
|
||||||
class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
|
class FaderPort : public ARDOUR::ControlProtocol {
|
||||||
public:
|
public:
|
||||||
FaderportMidiControlProtocol (ARDOUR::Session&);
|
FaderPort (ARDOUR::Session&);
|
||||||
virtual ~FaderportMidiControlProtocol();
|
virtual ~FaderPort();
|
||||||
|
|
||||||
int set_active (bool yn);
|
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);
|
void set_feedback_interval (ARDOUR::microseconds_t);
|
||||||
|
|
||||||
|
|
@ -84,6 +91,8 @@ class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
|
||||||
void next_bank ();
|
void next_bank ();
|
||||||
void prev_bank ();
|
void prev_bank ();
|
||||||
|
|
||||||
|
void reset_controllables ();
|
||||||
|
|
||||||
void set_motorised (bool);
|
void set_motorised (bool);
|
||||||
|
|
||||||
bool motorised () const {
|
bool motorised () const {
|
||||||
|
|
@ -96,11 +105,11 @@ class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
|
||||||
return _threshold;
|
return _threshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool device_active() const { return _device_active; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MIDI::Port* _input_port;
|
boost::shared_ptr<ARDOUR::AsyncMIDIPort> _input_port;
|
||||||
MIDI::Port* _output_port;
|
boost::shared_ptr<ARDOUR::AsyncMIDIPort> _output_port;
|
||||||
boost::shared_ptr<ARDOUR::Port> _async_in;
|
|
||||||
boost::shared_ptr<ARDOUR::Port> _async_out;
|
|
||||||
|
|
||||||
ARDOUR::microseconds_t _feedback_interval;
|
ARDOUR::microseconds_t _feedback_interval;
|
||||||
ARDOUR::microseconds_t last_feedback_time;
|
ARDOUR::microseconds_t last_feedback_time;
|
||||||
|
|
@ -109,10 +118,9 @@ class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
|
||||||
bool do_feedback;
|
bool do_feedback;
|
||||||
void send_feedback ();
|
void send_feedback ();
|
||||||
|
|
||||||
PBD::ScopedConnection midi_recv_connection;
|
PBD::ScopedConnectionList midi_connections;
|
||||||
void midi_receiver (MIDI::Parser &p, MIDI::byte *, size_t);
|
|
||||||
|
|
||||||
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;
|
std::string _current_binding;
|
||||||
uint32_t _bank_size;
|
uint32_t _bank_size;
|
||||||
|
|
@ -127,6 +135,82 @@ class FaderportMidiControlProtocol : public ARDOUR::ControlProtocol {
|
||||||
|
|
||||||
mutable void *gui;
|
mutable void *gui;
|
||||||
void build_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 */
|
||||||
|
|
@ -20,27 +20,27 @@
|
||||||
#include <pbd/failed_constructor.h>
|
#include <pbd/failed_constructor.h>
|
||||||
|
|
||||||
#include "control_protocol/control_protocol.h"
|
#include "control_protocol/control_protocol.h"
|
||||||
#include "faderport_midi_protocol.h"
|
#include "faderport.h"
|
||||||
|
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
|
|
||||||
static ControlProtocol*
|
static ControlProtocol*
|
||||||
new_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/, Session* s)
|
new_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/, Session* s)
|
||||||
{
|
{
|
||||||
FaderportMidiControlProtocol* fmcp;
|
FaderPort* fp;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fmcp = new FaderportMidiControlProtocol (*s);
|
fp = new FaderPort (*s);
|
||||||
} catch (failed_constructor& err) {
|
} catch (failed_constructor& err) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fmcp->set_active (true)) {
|
if (fp->set_active (true)) {
|
||||||
delete fmcp;
|
delete fp;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmcp;
|
return fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -52,7 +52,7 @@ delete_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/, Contr
|
||||||
static bool
|
static bool
|
||||||
probe_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/)
|
probe_faderport_midi_protocol (ControlProtocolDescriptor* /*descriptor*/)
|
||||||
{
|
{
|
||||||
return FaderportMidiControlProtocol::probe ();
|
return FaderPort::probe ();
|
||||||
}
|
}
|
||||||
|
|
||||||
static ControlProtocolDescriptor faderport_midi_descriptor = {
|
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/gtk_ui.h"
|
||||||
#include "gtkmm2ext/utils.h"
|
#include "gtkmm2ext/utils.h"
|
||||||
|
|
||||||
#include "faderport_midi_protocol.h"
|
#include "faderport.h"
|
||||||
|
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
class GMCPGUI : public Gtk::VBox
|
class GMCPGUI : public Gtk::VBox
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
GMCPGUI (FaderportMidiControlProtocol&);
|
GMCPGUI (FaderPort&);
|
||||||
~GMCPGUI ();
|
~GMCPGUI ();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FaderportMidiControlProtocol& cp;
|
FaderPort& cp;
|
||||||
Gtk::ComboBoxText map_combo;
|
Gtk::ComboBoxText map_combo;
|
||||||
Gtk::Adjustment bank_adjustment;
|
Gtk::Adjustment bank_adjustment;
|
||||||
Gtk::SpinButton bank_spinner;
|
Gtk::SpinButton bank_spinner;
|
||||||
|
|
@ -63,17 +63,17 @@ using namespace Gtk;
|
||||||
using namespace Gtkmm2ext;
|
using namespace Gtkmm2ext;
|
||||||
|
|
||||||
void*
|
void*
|
||||||
FaderportMidiControlProtocol::get_gui () const
|
FaderPort::get_gui () const
|
||||||
{
|
{
|
||||||
if (!gui) {
|
if (!gui) {
|
||||||
const_cast<FaderportMidiControlProtocol*>(this)->build_gui ();
|
const_cast<FaderPort*>(this)->build_gui ();
|
||||||
}
|
}
|
||||||
static_cast<Gtk::VBox*>(gui)->show_all();
|
static_cast<Gtk::VBox*>(gui)->show_all();
|
||||||
return gui;
|
return gui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FaderportMidiControlProtocol::tear_down_gui ()
|
FaderPort::tear_down_gui ()
|
||||||
{
|
{
|
||||||
if (gui) {
|
if (gui) {
|
||||||
Gtk::Widget *w = static_cast<Gtk::VBox*>(gui)->get_parent();
|
Gtk::Widget *w = static_cast<Gtk::VBox*>(gui)->get_parent();
|
||||||
|
|
@ -87,14 +87,14 @@ FaderportMidiControlProtocol::tear_down_gui ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FaderportMidiControlProtocol::build_gui ()
|
FaderPort::build_gui ()
|
||||||
{
|
{
|
||||||
gui = (void*) new GMCPGUI (*this);
|
gui = (void*) new GMCPGUI (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*--------------------*/
|
/*--------------------*/
|
||||||
|
|
||||||
GMCPGUI::GMCPGUI (FaderportMidiControlProtocol& p)
|
GMCPGUI::GMCPGUI (FaderPort& p)
|
||||||
: cp (p)
|
: cp (p)
|
||||||
, bank_adjustment (1, 1, 100, 1, 10)
|
, bank_adjustment (1, 1, 100, 1, 10)
|
||||||
, bank_spinner (bank_adjustment)
|
, bank_spinner (bank_adjustment)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ def configure(conf):
|
||||||
def build(bld):
|
def build(bld):
|
||||||
obj = bld(features = 'cxx cxxshlib')
|
obj = bld(features = 'cxx cxxshlib')
|
||||||
obj.source = '''
|
obj.source = '''
|
||||||
faderport_midi_protocol.cc
|
faderport.cc
|
||||||
fmcp_gui.cc
|
fmcp_gui.cc
|
||||||
faderport_interface.cc
|
faderport_interface.cc
|
||||||
'''
|
'''
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue