US2400: add us2400 files to repository.
This commit is contained in:
2
libs/surfaces/us2400/TODO
Normal file
2
libs/surfaces/us2400/TODO
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
MB: allow control of strip params when a mix-bus or master is selected
|
||||
142
libs/surfaces/us2400/button.cc
Normal file
142
libs/surfaces/us2400/button.cc
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
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 <glib.h>
|
||||
|
||||
#include "ardour/ardour.h"
|
||||
|
||||
#include "button.h"
|
||||
#include "surface.h"
|
||||
#include "control_group.h"
|
||||
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
Control*
|
||||
Button::factory (Surface& surface, Button::ID bid, int id, const std::string& name, Group& group)
|
||||
{
|
||||
Button* b = new Button (surface, bid, id, name, group);
|
||||
/* store button with the device-specific ID */
|
||||
surface.buttons[id] = b;
|
||||
surface.controls.push_back (b);
|
||||
group.add (*b);
|
||||
return b;
|
||||
}
|
||||
|
||||
void
|
||||
Button::pressed ()
|
||||
{
|
||||
press_time = ARDOUR::get_microseconds ();
|
||||
}
|
||||
|
||||
void
|
||||
Button::released ()
|
||||
{
|
||||
press_time = 0;
|
||||
}
|
||||
|
||||
int32_t
|
||||
Button::long_press_count ()
|
||||
{
|
||||
if (press_time == 0) {
|
||||
return -1; /* button is not pressed */
|
||||
}
|
||||
|
||||
const ARDOUR::microseconds_t delta = ARDOUR::get_microseconds () - press_time;
|
||||
|
||||
if (delta < 500000) {
|
||||
return 0;
|
||||
} else if (delta < 1000000) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
int
|
||||
Button::name_to_id (const std::string& name)
|
||||
{
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Send")) { return Send; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Pan")) { return Pan; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Bank Left")) { return Left; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Bank Right")) { return Right; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Flip")) { return Flip; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "F1")) { return F1; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "F2")) { return F2; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "F3")) { return F3; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "F4")) { return F4; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "F5")) { return F5; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "F6")) { return F6; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Shift")) { return Shift; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Drop")) { return Drop; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Clear Solo")) { return ClearSolo; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Rewind")) { return Rewind; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Ffwd")) { return Ffwd; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Stop")) { return Stop; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Play")) { return Play; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Record")) { return Record; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Scrub")) { return Scrub; }
|
||||
|
||||
/* Strip buttons */
|
||||
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Solo")) { return Solo; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Mute")) { return Mute; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Select")) { return Select; }
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Fader Touch")) { return FaderTouch; }
|
||||
|
||||
/* Master Fader button */
|
||||
|
||||
if (!g_ascii_strcasecmp (name.c_str(), "Master Fader Touch")) { return MasterFaderTouch; }
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string
|
||||
Button::id_to_name (Button::ID id)
|
||||
{
|
||||
if (id == Send) { return "Send"; }
|
||||
if (id == Pan) { return "Pan"; }
|
||||
if (id == Left) { return "Bank Left"; }
|
||||
if (id == Right) { return "Bank Right"; }
|
||||
if (id == Flip) { return "Flip"; }
|
||||
if (id == F1) { return "F1"; }
|
||||
if (id == F2) { return "F2"; }
|
||||
if (id == F3) { return "F3"; }
|
||||
if (id == F4) { return "F4"; }
|
||||
if (id == F5) { return "F5"; }
|
||||
if (id == F6) { return "F6"; }
|
||||
if (id == Shift) { return "Shift"; }
|
||||
if (id == Drop) { return "Drop"; }
|
||||
if (id == ClearSolo) { return "Clear Solo"; }
|
||||
if (id == Rewind) { return "Rewind"; }
|
||||
if (id == Ffwd) { return "FFwd"; }
|
||||
if (id == Stop) { return "Stop"; }
|
||||
if (id == Play) { return "Play"; }
|
||||
if (id == Record) { return "Record"; }
|
||||
if (id == Scrub) { return "Scrub"; }
|
||||
|
||||
if (id == Solo) { return "Solo"; }
|
||||
if (id == Mute) { return "Mute"; }
|
||||
if (id == Select) { return "Select"; }
|
||||
if (id == FaderTouch) { return "Fader Touch"; }
|
||||
|
||||
if (id == MasterFaderTouch) { return "Master Fader Touch"; }
|
||||
|
||||
return "???";
|
||||
}
|
||||
121
libs/surfaces/us2400/button.h
Normal file
121
libs/surfaces/us2400/button.h
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_us2400_control_protocol_button_h__
|
||||
#define __ardour_us2400_control_protocol_button_h__
|
||||
|
||||
#include "ardour/types.h"
|
||||
|
||||
#include "controls.h"
|
||||
#include "led.h"
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
class Surface;
|
||||
|
||||
class Button : public Control
|
||||
{
|
||||
public:
|
||||
/* These values uniquely identify each possible button that an MCP device may
|
||||
send. Each DeviceInfo object contains its own set of button definitions that
|
||||
define what device ID will be sent for each button, and there is no reason
|
||||
for them to be the same. */
|
||||
|
||||
enum ID {
|
||||
/* Global Buttons */
|
||||
|
||||
Scrub,
|
||||
F1,
|
||||
F2,
|
||||
F3,
|
||||
F4,
|
||||
F5,
|
||||
F6,
|
||||
Rewind,
|
||||
Ffwd,
|
||||
Stop,
|
||||
Play,
|
||||
Record,
|
||||
Left,
|
||||
Right,
|
||||
Flip,
|
||||
|
||||
FinalGlobalButton,
|
||||
|
||||
|
||||
/* Global buttons that users should not redefine */
|
||||
|
||||
Drop,
|
||||
Send,
|
||||
Pan,
|
||||
ClearSolo,
|
||||
Shift,
|
||||
Option,
|
||||
Ctrl,
|
||||
CmdAlt,
|
||||
|
||||
/* Strip buttons */
|
||||
|
||||
Solo,
|
||||
Mute,
|
||||
Select,
|
||||
FaderTouch,
|
||||
|
||||
/* Master fader */
|
||||
|
||||
MasterFaderTouch,
|
||||
};
|
||||
|
||||
|
||||
Button (Surface& s, ID bid, int did, std::string name, Group & group)
|
||||
: Control (did, name, group)
|
||||
, _surface (s)
|
||||
, _bid (bid)
|
||||
, _led (did, name + "_led", group)
|
||||
, press_time (0) {}
|
||||
|
||||
MidiByteArray zero() { return _led.zero (); }
|
||||
MidiByteArray set_state (LedState ls) { return _led.set_state (ls); }
|
||||
|
||||
ID bid() const { return _bid; }
|
||||
|
||||
static Control* factory (Surface& surface, Button::ID bid, int id, const std::string&, Group& group);
|
||||
static int name_to_id (const std::string& name);
|
||||
static std::string id_to_name (Button::ID);
|
||||
|
||||
Surface& surface() const { return _surface; }
|
||||
|
||||
void pressed ();
|
||||
void released ();
|
||||
|
||||
int32_t long_press_count ();
|
||||
|
||||
private:
|
||||
Surface& _surface;
|
||||
ID _bid; /* device independent button ID */
|
||||
Led _led;
|
||||
ARDOUR::microseconds_t press_time;
|
||||
};
|
||||
|
||||
} // US2400 namespace
|
||||
} // ArdourSurface namespace
|
||||
|
||||
#endif
|
||||
44
libs/surfaces/us2400/control_group.h
Normal file
44
libs/surfaces/us2400/control_group.h
Normal file
@@ -0,0 +1,44 @@
|
||||
#ifndef __ardour_us2400_control_protocol_control_group_h__
|
||||
#define __ardour_us2400_control_protocol_control_group_h__
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ArdourSurface {
|
||||
namespace US2400 {
|
||||
|
||||
class Control;
|
||||
|
||||
/**
|
||||
This is a loose group of controls, eg cursor buttons,
|
||||
transport buttons, functions buttons etc.
|
||||
*/
|
||||
class Group
|
||||
{
|
||||
public:
|
||||
Group (const std::string & name)
|
||||
: _name (name) {}
|
||||
|
||||
virtual ~Group() {}
|
||||
|
||||
virtual bool is_strip() const { return false; }
|
||||
virtual bool is_master() const { return false; }
|
||||
|
||||
virtual void add (Control & control);
|
||||
|
||||
const std::string & name() const { return _name; }
|
||||
void set_name (const std::string & rhs) { _name = rhs; }
|
||||
|
||||
typedef std::vector<Control*> Controls;
|
||||
const Controls & controls() const { return _controls; }
|
||||
|
||||
protected:
|
||||
Controls _controls;
|
||||
|
||||
private:
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
127
libs/surfaces/us2400/controls.cc
Normal file
127
libs/surfaces/us2400/controls.cc
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
|
||||
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 <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "ardour/automation_control.h"
|
||||
#include "pbd/enumwriter.h"
|
||||
|
||||
#include "controls.h"
|
||||
#include "types.h"
|
||||
#include "surface.h"
|
||||
#include "control_group.h"
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "pot.h"
|
||||
#include "fader.h"
|
||||
#include "jog.h"
|
||||
#include "meter.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
using ARDOUR::AutomationControl;
|
||||
|
||||
void Group::add (Control& control)
|
||||
{
|
||||
_controls.push_back (&control);
|
||||
}
|
||||
|
||||
Control::Control (int id, std::string name, Group & group)
|
||||
: _id (id)
|
||||
, _name (name)
|
||||
, _group (group)
|
||||
, _in_use (false)
|
||||
{
|
||||
}
|
||||
|
||||
/** @return true if the control is in use, or false otherwise.
|
||||
Buttons are `in use' when they are held down.
|
||||
Faders with touch support are `in use' when they are being touched.
|
||||
Pots, or faders without touch support, are `in use' from the first move
|
||||
event until a timeout after the last move event.
|
||||
*/
|
||||
bool
|
||||
Control::in_use () const
|
||||
{
|
||||
return _in_use;
|
||||
}
|
||||
|
||||
void
|
||||
Control::set_in_use (bool in_use)
|
||||
{
|
||||
_in_use = in_use;
|
||||
}
|
||||
|
||||
void
|
||||
Control::set_control (boost::shared_ptr<AutomationControl> ac)
|
||||
{
|
||||
normal_ac = ac;
|
||||
}
|
||||
|
||||
void
|
||||
Control::set_value (float val, PBD::Controllable::GroupControlDisposition group_override)
|
||||
{
|
||||
if (normal_ac) {
|
||||
normal_ac->set_value (normal_ac->interface_to_internal (val), group_override);
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
Control::get_value ()
|
||||
{
|
||||
if (!normal_ac) {
|
||||
return 0.0f;
|
||||
}
|
||||
return normal_ac->internal_to_interface (normal_ac->get_value());
|
||||
}
|
||||
|
||||
void
|
||||
Control::start_touch (double when)
|
||||
{
|
||||
if (normal_ac) {
|
||||
return normal_ac->start_touch (when);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Control::stop_touch (double when)
|
||||
{
|
||||
if (normal_ac) {
|
||||
return normal_ac->stop_touch (when);
|
||||
}
|
||||
}
|
||||
|
||||
ostream & operator << (ostream & os, const ArdourSurface::US2400::Control & control)
|
||||
{
|
||||
os << typeid (control).name();
|
||||
os << " { ";
|
||||
os << "name: " << control.name();
|
||||
os << ", ";
|
||||
os << "id: " << "0x" << setw(2) << setfill('0') << hex << control.id() << setfill(' ');
|
||||
os << ", ";
|
||||
os << "group: " << control.group().name();
|
||||
os << " }";
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
95
libs/surfaces/us2400/controls.h
Normal file
95
libs/surfaces/us2400/controls.h
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __us2400_controls_h__
|
||||
#define __us2400_controls_h__
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <boost/smart_ptr.hpp>
|
||||
|
||||
#include "pbd/controllable.h"
|
||||
#include "pbd/signals.h"
|
||||
|
||||
#include "us2400_control_exception.h"
|
||||
#include "midi_byte_array.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class AutomationControl;
|
||||
}
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
class Strip;
|
||||
class Group;
|
||||
class Surface;
|
||||
|
||||
class Control {
|
||||
public:
|
||||
Control (int id, std::string name, Group& group);
|
||||
virtual ~Control() {}
|
||||
|
||||
int id() const { return _id; }
|
||||
const std::string & name() const { return _name; }
|
||||
Group & group() const { return _group; }
|
||||
|
||||
bool in_use () const;
|
||||
void set_in_use (bool);
|
||||
|
||||
// Keep track of the timeout so it can be updated with more incoming events
|
||||
sigc::connection in_use_connection;
|
||||
|
||||
virtual MidiByteArray zero() = 0;
|
||||
|
||||
/** If we are doing an in_use timeout for a fader without touch, this
|
||||
* is its touch button control; otherwise 0.
|
||||
*/
|
||||
Control* in_use_touch_control;
|
||||
|
||||
boost::shared_ptr<ARDOUR::AutomationControl> control () const { return normal_ac; }
|
||||
virtual void set_control (boost::shared_ptr<ARDOUR::AutomationControl>);
|
||||
virtual void reset_control () { normal_ac.reset(); }
|
||||
|
||||
float get_value ();
|
||||
void set_value (float val, PBD::Controllable::GroupControlDisposition gcd = PBD::Controllable::UseGroup);
|
||||
|
||||
virtual void start_touch (double when);
|
||||
virtual void stop_touch (double when);
|
||||
|
||||
protected:
|
||||
boost::shared_ptr<ARDOUR::AutomationControl> normal_ac;
|
||||
|
||||
private:
|
||||
int _id; /* possibly device-dependent ID */
|
||||
std::string _name;
|
||||
Group& _group;
|
||||
bool _in_use;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream & operator << (std::ostream & os, const ArdourSurface::US2400::Control & control);
|
||||
|
||||
#endif /* __us2400_controls_h__ */
|
||||
366
libs/surfaces/us2400/device_info.cc
Normal file
366
libs/surfaces/us2400/device_info.cc
Normal file
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
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 <cstdlib>
|
||||
#include <cstring>
|
||||
#include <glibmm/miscutils.h>
|
||||
|
||||
#include "pbd/xml++.h"
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/file_utils.h"
|
||||
#include "pbd/convert.h"
|
||||
#include "pbd/stl_delete.h"
|
||||
|
||||
#include "ardour/filesystem_paths.h"
|
||||
|
||||
#include "device_info.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
std::map<std::string,DeviceInfo> DeviceInfo::device_info;
|
||||
|
||||
DeviceInfo::DeviceInfo()
|
||||
: _strip_cnt (8)
|
||||
, _extenders (3)
|
||||
, _master_position (0)
|
||||
, _has_two_character_display (false)
|
||||
, _has_master_fader (true)
|
||||
, _has_timecode_display (false)
|
||||
, _has_global_controls (true)
|
||||
, _has_jog_wheel (true)
|
||||
, _has_touch_sense_faders (true)
|
||||
, _uses_logic_control_buttons (false)
|
||||
, _no_handshake (false)
|
||||
, _has_meters (true)
|
||||
, _has_separate_meters (true)
|
||||
, _device_type (MCU)
|
||||
, _name (X_("US2400"))
|
||||
{
|
||||
us2400_control_buttons ();
|
||||
}
|
||||
|
||||
DeviceInfo::~DeviceInfo()
|
||||
{
|
||||
}
|
||||
|
||||
GlobalButtonInfo&
|
||||
DeviceInfo::get_global_button(Button::ID id)
|
||||
{
|
||||
GlobalButtonsInfo::iterator it;
|
||||
|
||||
it = _global_buttons.find (id);
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::string&
|
||||
DeviceInfo::get_global_button_name(Button::ID id)
|
||||
{
|
||||
GlobalButtonsInfo::iterator it;
|
||||
|
||||
it = _global_buttons.find (id);
|
||||
if (it == _global_buttons.end ()) {
|
||||
_global_button_name = "";
|
||||
return _global_button_name;
|
||||
} else {
|
||||
return it->second.label;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeviceInfo::us2400_control_buttons ()
|
||||
{
|
||||
_global_buttons.clear ();
|
||||
shared_buttons ();
|
||||
}
|
||||
|
||||
void
|
||||
DeviceInfo::logic_control_buttons ()
|
||||
{
|
||||
_global_buttons.clear ();
|
||||
shared_buttons ();
|
||||
}
|
||||
|
||||
void
|
||||
DeviceInfo::shared_buttons ()
|
||||
{
|
||||
// US-2499 button notes:
|
||||
// CHAN button sends nothing. it inititates a dumb 0..127 knob mode for the 24 knobs
|
||||
// PAN sends the regular pan/surround message. this tells our strips to send the pan knob position
|
||||
// AUX1-6 all send the same 0x29 + 0x21 message, I believe the surface uses this to captures knob info, somehow
|
||||
|
||||
_global_buttons[Button::Pan] = GlobalButtonInfo ("Pan/Surround", "assignment", 0x2a); // US-2400: this is sent (on&off in one msg) from the Pan button
|
||||
|
||||
_global_buttons[Button::Left] = GlobalButtonInfo ("Bank Left", "bank", 0x2e);
|
||||
_global_buttons[Button::Right] = GlobalButtonInfo ("Bank Right", "bank", 0x2f);
|
||||
|
||||
_global_buttons[Button::Flip] = GlobalButtonInfo ("Flip", "assignment", 0x32);
|
||||
|
||||
_global_buttons[Button::F1] = GlobalButtonInfo ("F1", "function select", 0x36);
|
||||
_global_buttons[Button::F2] = GlobalButtonInfo ("F2", "function select", 0x37);
|
||||
_global_buttons[Button::F3] = GlobalButtonInfo ("F3", "function select", 0x38);
|
||||
_global_buttons[Button::F4] = GlobalButtonInfo ("F4", "function select", 0x39);
|
||||
_global_buttons[Button::F5] = GlobalButtonInfo ("F5", "function select", 0x3a);
|
||||
_global_buttons[Button::F6] = GlobalButtonInfo ("F6", "function select", 0x3b);
|
||||
|
||||
|
||||
_global_buttons[Button::Shift] = GlobalButtonInfo ("Shift", "modifiers", 0x46);
|
||||
_global_buttons[Button::Option] = GlobalButtonInfo ("Option", "modifiers", 0x47); //There is no physical Option button, but US2400 sends Option+ track Solo == solo clear
|
||||
|
||||
_global_buttons[Button::Drop] = GlobalButtonInfo ("Drop", "transport", 0x57); // US-2400: combined with ffwd/rew to call IN/OUT
|
||||
|
||||
_global_buttons[Button::Rewind] = GlobalButtonInfo ("Rewind", "transport", 0x5b); // US-2400: if "Drop" 0x57 is held, this is IN
|
||||
_global_buttons[Button::Ffwd] = GlobalButtonInfo ("Fast Fwd", "transport", 0x5c); // US-2400: if "Drop 0x57 is held, this is OUT
|
||||
_global_buttons[Button::Stop] = GlobalButtonInfo ("Stop", "transport", 0x5d);
|
||||
_global_buttons[Button::Play] = GlobalButtonInfo ("Play", "transport", 0x5e);
|
||||
_global_buttons[Button::Record] = GlobalButtonInfo ("Record", "transport", 0x5f);
|
||||
|
||||
_global_buttons[Button::Scrub] = GlobalButtonInfo ("Scrub", "cursor", 0x65);
|
||||
|
||||
_strip_buttons[Button::Solo] = StripButtonInfo (0x08, "Solo"); //combined with Option" to do solo clear
|
||||
_strip_buttons[Button::Mute] = StripButtonInfo (0x10, "Mute");
|
||||
_strip_buttons[Button::Select] = StripButtonInfo (0x18, "Select");
|
||||
|
||||
_strip_buttons[Button::FaderTouch] = StripButtonInfo (0x68, "Fader Touch");
|
||||
|
||||
_global_buttons[Button::MasterFaderTouch] = GlobalButtonInfo ("Master Fader Touch", "master", 0x70);
|
||||
}
|
||||
|
||||
int
|
||||
DeviceInfo::set_state (const XMLNode& node, int /* version */)
|
||||
{
|
||||
const XMLProperty* prop;
|
||||
const XMLNode* child;
|
||||
|
||||
if (node.name() != "US-2400Device") {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((child = node.child ("LogicControlButtons")) != 0) {
|
||||
if (child->get_property ("value", _uses_logic_control_buttons)) {
|
||||
if (_uses_logic_control_buttons) {
|
||||
logic_control_buttons ();
|
||||
} else {
|
||||
us2400_control_buttons ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((child = node.child ("Buttons")) != 0) {
|
||||
XMLNodeConstIterator i;
|
||||
const XMLNodeList& nlist (child->children());
|
||||
|
||||
std::string name;
|
||||
for (i = nlist.begin(); i != nlist.end(); ++i) {
|
||||
if ((*i)->name () == "GlobalButton") {
|
||||
if ((*i)->get_property ("name", name)) {
|
||||
int id = Button::name_to_id (name);
|
||||
if (id >= 0) {
|
||||
Button::ID bid = (Button::ID)id;
|
||||
int32_t id;
|
||||
if ((*i)->get_property ("id", id)) {
|
||||
std::map<Button::ID, GlobalButtonInfo>::iterator b = _global_buttons.find (bid);
|
||||
if (b != _global_buttons.end ()) {
|
||||
b->second.id = id;
|
||||
(*i)->get_property ("label", b->second.label);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if ((*i)->name () == "StripButton") {
|
||||
if ((*i)->get_property ("name", name)) {
|
||||
int id = Button::name_to_id (name);
|
||||
if (id >= 0) {
|
||||
Button::ID bid = (Button::ID)id;
|
||||
int32_t base_id;
|
||||
if ((*i)->get_property ("baseid", base_id)) {
|
||||
std::map<Button::ID, StripButtonInfo>::iterator b = _strip_buttons.find (bid);
|
||||
if (b != _strip_buttons.end ()) {
|
||||
b->second.base_id = base_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const string&
|
||||
DeviceInfo::name() const
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DeviceInfo::strip_cnt() const
|
||||
{
|
||||
return _strip_cnt;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DeviceInfo::extenders() const
|
||||
{
|
||||
return _extenders;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DeviceInfo::master_position() const
|
||||
{
|
||||
return _master_position;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceInfo::has_master_fader() const
|
||||
{
|
||||
return _has_master_fader;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceInfo::has_meters() const
|
||||
{
|
||||
return _has_meters;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceInfo::has_separate_meters() const
|
||||
{
|
||||
return _has_separate_meters;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceInfo::has_two_character_display() const
|
||||
{
|
||||
return _has_two_character_display;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceInfo::has_timecode_display () const
|
||||
{
|
||||
return _has_timecode_display;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceInfo::has_global_controls () const
|
||||
{
|
||||
return _has_global_controls;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceInfo::has_jog_wheel () const
|
||||
{
|
||||
return _has_jog_wheel;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceInfo::no_handshake () const
|
||||
{
|
||||
return _no_handshake;
|
||||
}
|
||||
|
||||
bool
|
||||
DeviceInfo::has_touch_sense_faders () const
|
||||
{
|
||||
return _has_touch_sense_faders;
|
||||
}
|
||||
|
||||
static const char * const devinfo_env_variable_name = "ARDOUR_MCP_PATH";
|
||||
static const char* const devinfo_dir_name = "mcp";
|
||||
static const char* const devinfo_suffix = ".device";
|
||||
|
||||
static Searchpath
|
||||
devinfo_search_path ()
|
||||
{
|
||||
bool devinfo_path_defined = false;
|
||||
std::string spath_env (Glib::getenv (devinfo_env_variable_name, devinfo_path_defined));
|
||||
|
||||
if (devinfo_path_defined) {
|
||||
return spath_env;
|
||||
}
|
||||
|
||||
Searchpath spath (ardour_data_search_path());
|
||||
spath.add_subdirectory_to_paths(devinfo_dir_name);
|
||||
|
||||
return spath;
|
||||
}
|
||||
|
||||
static bool
|
||||
devinfo_filter (const string &str, void* /*arg*/)
|
||||
{
|
||||
return (str.length() > strlen(devinfo_suffix) &&
|
||||
str.find (devinfo_suffix) == (str.length() - strlen (devinfo_suffix)));
|
||||
}
|
||||
|
||||
void
|
||||
DeviceInfo::reload_device_info ()
|
||||
{
|
||||
vector<string> s;
|
||||
vector<string> devinfos;
|
||||
Searchpath spath (devinfo_search_path());
|
||||
|
||||
find_files_matching_filter (devinfos, spath, devinfo_filter, 0, false, true);
|
||||
device_info.clear ();
|
||||
|
||||
if (devinfos.empty()) {
|
||||
error << "No MCP device info files found using " << spath.to_string() << endmsg;
|
||||
std::cerr << "No MCP device info files found using " << spath.to_string() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (vector<string>::iterator i = devinfos.begin(); i != devinfos.end(); ++i) {
|
||||
string fullpath = *i;
|
||||
DeviceInfo di; // has to be initial every loop or info from last added.
|
||||
|
||||
XMLTree tree;
|
||||
|
||||
if (!tree.read (fullpath.c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
XMLNode* root = tree.root ();
|
||||
if (!root) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (di.set_state (*root, 3000) == 0) { /* version is ignored for now */
|
||||
device_info[di.name()] = di;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<< (std::ostream& os, const US2400::DeviceInfo& di)
|
||||
{
|
||||
os << di.name() << ' '
|
||||
<< di.strip_cnt() << ' '
|
||||
<< di.extenders() << ' '
|
||||
<< di.master_position() << ' '
|
||||
;
|
||||
return os;
|
||||
}
|
||||
132
libs/surfaces/us2400/device_info.h
Normal file
132
libs/surfaces/us2400/device_info.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_us2400_control_protocol_device_info_h__
|
||||
#define __ardour_us2400_control_protocol_device_info_h__
|
||||
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "button.h"
|
||||
|
||||
class XMLNode;
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
struct GlobalButtonInfo {
|
||||
std::string label; // visible to user
|
||||
std::string group; // in case we want to present in a GUI
|
||||
int32_t id; // value sent by device
|
||||
|
||||
GlobalButtonInfo () : id (-1) {}
|
||||
GlobalButtonInfo (const std::string& l, const std::string& g, uint32_t i)
|
||||
: label (l), group (g), id (i) {}
|
||||
};
|
||||
|
||||
struct StripButtonInfo {
|
||||
int32_t base_id;
|
||||
std::string name;
|
||||
|
||||
StripButtonInfo () : base_id (-1) {}
|
||||
StripButtonInfo (uint32_t i, const std::string& n)
|
||||
: base_id (i), name (n) {}
|
||||
};
|
||||
|
||||
class DeviceInfo
|
||||
{
|
||||
public:
|
||||
enum DeviceType {
|
||||
MCU = 0x14,
|
||||
MCXT = 0x15,
|
||||
LC = 0x10,
|
||||
LCXT = 0x11,
|
||||
HUI = 0x5
|
||||
};
|
||||
|
||||
DeviceInfo();
|
||||
~DeviceInfo();
|
||||
|
||||
int set_state (const XMLNode&, int version);
|
||||
|
||||
DeviceType device_type() const { return _device_type; }
|
||||
uint32_t strip_cnt () const;
|
||||
uint32_t extenders() const;
|
||||
uint32_t master_position() const;
|
||||
bool has_two_character_display() const;
|
||||
bool has_master_fader () const;
|
||||
bool has_timecode_display() const;
|
||||
bool has_global_controls() const;
|
||||
bool has_jog_wheel () const;
|
||||
bool has_touch_sense_faders() const;
|
||||
bool no_handshake() const;
|
||||
bool has_meters() const;
|
||||
bool has_separate_meters() const;
|
||||
bool us2400() const { return _us2400; }
|
||||
const std::string& name() const;
|
||||
|
||||
static std::map<std::string,DeviceInfo> device_info;
|
||||
static void reload_device_info();
|
||||
|
||||
std::string& get_global_button_name(Button::ID);
|
||||
GlobalButtonInfo& get_global_button(Button::ID);
|
||||
|
||||
typedef std::map<Button::ID,GlobalButtonInfo> GlobalButtonsInfo;
|
||||
typedef std::map<Button::ID,StripButtonInfo> StripButtonsInfo;
|
||||
|
||||
const GlobalButtonsInfo& global_buttons() const { return _global_buttons; }
|
||||
const StripButtonsInfo& strip_buttons() const { return _strip_buttons; }
|
||||
|
||||
private:
|
||||
uint32_t _strip_cnt;
|
||||
uint32_t _extenders;
|
||||
uint32_t _master_position;
|
||||
bool _has_two_character_display;
|
||||
bool _has_master_fader;
|
||||
bool _has_timecode_display;
|
||||
bool _has_global_controls;
|
||||
bool _has_jog_wheel;
|
||||
bool _has_touch_sense_faders;
|
||||
bool _uses_logic_control_buttons;
|
||||
bool _no_handshake;
|
||||
bool _has_meters;
|
||||
bool _has_separate_meters;
|
||||
bool _us2400;
|
||||
DeviceType _device_type;
|
||||
std::string _name;
|
||||
std::string _global_button_name;
|
||||
|
||||
GlobalButtonsInfo _global_buttons;
|
||||
StripButtonsInfo _strip_buttons;
|
||||
|
||||
void logic_control_buttons ();
|
||||
void us2400_control_buttons ();
|
||||
void shared_buttons ();
|
||||
};
|
||||
|
||||
|
||||
} // US2400 namespace
|
||||
} // ArdourSurface namespace
|
||||
|
||||
std::ostream& operator<< (std::ostream& os, const ArdourSurface::US2400::DeviceInfo& di);
|
||||
|
||||
#endif /* __ardour_us2400_control_protocol_device_info_h__ */
|
||||
329
libs/surfaces/us2400/device_profile.cc
Normal file
329
libs/surfaces/us2400/device_profile.cc
Normal file
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
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 <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <glibmm/miscutils.h>
|
||||
|
||||
#include "pbd/xml++.h"
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/file_utils.h"
|
||||
#include "pbd/stl_delete.h"
|
||||
#include "pbd/replace_all.h"
|
||||
|
||||
#include "ardour/filesystem_paths.h"
|
||||
|
||||
#include "us2400_control_protocol.h"
|
||||
#include "device_profile.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
std::map<std::string,DeviceProfile> DeviceProfile::device_profiles;
|
||||
const std::string DeviceProfile::edited_indicator (" (edited)");
|
||||
const std::string DeviceProfile::default_profile_name ("User");
|
||||
|
||||
DeviceProfile::DeviceProfile (const string& n)
|
||||
: _name (n)
|
||||
, edited (false)
|
||||
{
|
||||
}
|
||||
|
||||
DeviceProfile::~DeviceProfile()
|
||||
{
|
||||
}
|
||||
|
||||
static const char * const devprofile_env_variable_name = "ARDOUR_MCP_PATH";
|
||||
static const char* const devprofile_dir_name = "us2400";
|
||||
static const char* const devprofile_suffix = ".profile";
|
||||
|
||||
static Searchpath
|
||||
devprofile_search_path ()
|
||||
{
|
||||
bool devprofile_path_defined = false;
|
||||
std::string spath_env (Glib::getenv (devprofile_env_variable_name, devprofile_path_defined));
|
||||
|
||||
if (devprofile_path_defined) {
|
||||
return spath_env;
|
||||
}
|
||||
|
||||
Searchpath spath (ardour_data_search_path());
|
||||
spath.add_subdirectory_to_paths(devprofile_dir_name);
|
||||
|
||||
return spath;
|
||||
}
|
||||
|
||||
static std::string
|
||||
user_devprofile_directory ()
|
||||
{
|
||||
return Glib::build_filename (user_config_directory(), devprofile_dir_name);
|
||||
}
|
||||
|
||||
static bool
|
||||
devprofile_filter (const string &str, void* /*arg*/)
|
||||
{
|
||||
return (str.length() > strlen(devprofile_suffix) &&
|
||||
str.find (devprofile_suffix) == (str.length() - strlen (devprofile_suffix)));
|
||||
}
|
||||
|
||||
void
|
||||
DeviceProfile::reload_device_profiles ()
|
||||
{
|
||||
vector<string> s;
|
||||
vector<string> devprofiles;
|
||||
Searchpath spath (devprofile_search_path());
|
||||
|
||||
find_files_matching_filter (devprofiles, spath, devprofile_filter, 0, false, true);
|
||||
device_profiles.clear ();
|
||||
|
||||
if (devprofiles.empty()) {
|
||||
error << "No MCP device info files found using " << spath.to_string() << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
for (vector<string>::iterator i = devprofiles.begin(); i != devprofiles.end(); ++i) {
|
||||
string fullpath = *i;
|
||||
DeviceProfile dp; // has to be initial every loop or info from last added.
|
||||
|
||||
XMLTree tree;
|
||||
|
||||
if (!tree.read (fullpath.c_str())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
XMLNode* root = tree.root ();
|
||||
if (!root) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dp.set_state (*root, 3000) == 0) { /* version is ignored for now */
|
||||
dp.set_path (fullpath);
|
||||
device_profiles[dp.name()] = dp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
DeviceProfile::set_state (const XMLNode& node, int /* version */)
|
||||
{
|
||||
const XMLProperty* prop;
|
||||
const XMLNode* child;
|
||||
|
||||
if (node.name() != "US2400DeviceProfile") {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* name is mandatory */
|
||||
|
||||
if ((child = node.child ("Name")) == 0 || (prop = child->property ("value")) == 0) {
|
||||
return -1;
|
||||
} else {
|
||||
_name = prop->value();
|
||||
}
|
||||
|
||||
if ((child = node.child ("Buttons")) != 0) {
|
||||
XMLNodeConstIterator i;
|
||||
const XMLNodeList& nlist (child->children());
|
||||
|
||||
for (i = nlist.begin(); i != nlist.end(); ++i) {
|
||||
|
||||
if ((*i)->name() == "Button") {
|
||||
|
||||
if ((prop = (*i)->property ("name")) == 0) {
|
||||
error << string_compose ("Button without name in device profile \"%1\" - ignored", _name) << endmsg;
|
||||
continue;
|
||||
}
|
||||
|
||||
int id = Button::name_to_id (prop->value());
|
||||
if (id < 0) {
|
||||
error << string_compose ("Unknown button ID \"%1\"", prop->value()) << endmsg;
|
||||
continue;
|
||||
}
|
||||
|
||||
Button::ID bid = (Button::ID) id;
|
||||
|
||||
ButtonActionMap::iterator b = _button_map.find (bid);
|
||||
|
||||
if (b == _button_map.end()) {
|
||||
b = _button_map.insert (_button_map.end(), std::pair<Button::ID,ButtonActions> (bid, ButtonActions()));
|
||||
}
|
||||
|
||||
(*i)->get_property ("plain", b->second.plain);
|
||||
(*i)->get_property ("shift", b->second.shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
edited = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
DeviceProfile::get_state () const
|
||||
{
|
||||
XMLNode* node = new XMLNode ("US2400DeviceProfile");
|
||||
XMLNode* child = new XMLNode ("Name");
|
||||
|
||||
child->set_property ("value", name());
|
||||
node->add_child_nocopy (*child);
|
||||
|
||||
if (_button_map.empty()) {
|
||||
return *node;
|
||||
}
|
||||
|
||||
XMLNode* buttons = new XMLNode ("Buttons");
|
||||
node->add_child_nocopy (*buttons);
|
||||
|
||||
for (ButtonActionMap::const_iterator b = _button_map.begin(); b != _button_map.end(); ++b) {
|
||||
XMLNode* n = new XMLNode ("Button");
|
||||
|
||||
n->set_property ("name", Button::id_to_name (b->first));
|
||||
|
||||
if (!b->second.plain.empty()) {
|
||||
n->set_property ("plain", b->second.plain);
|
||||
}
|
||||
if (!b->second.shift.empty()) {
|
||||
n->set_property ("shift", b->second.shift);
|
||||
}
|
||||
|
||||
buttons->add_child_nocopy (*n);
|
||||
}
|
||||
|
||||
return *node;
|
||||
}
|
||||
|
||||
string
|
||||
DeviceProfile::get_button_action (Button::ID id, int modifier_state) const
|
||||
{
|
||||
ButtonActionMap::const_iterator i = _button_map.find (id);
|
||||
|
||||
if (i == _button_map.end()) {
|
||||
return string();
|
||||
}
|
||||
|
||||
if (modifier_state == US2400Protocol::MODIFIER_SHIFT) {
|
||||
return i->second.shift;
|
||||
}
|
||||
|
||||
return i->second.plain;
|
||||
}
|
||||
|
||||
void
|
||||
DeviceProfile::set_button_action (Button::ID id, int modifier_state, const string& act)
|
||||
{
|
||||
ButtonActionMap::iterator i = _button_map.find (id);
|
||||
|
||||
if (i == _button_map.end()) {
|
||||
i = _button_map.insert (std::make_pair (id, ButtonActions())).first;
|
||||
}
|
||||
|
||||
string action (act);
|
||||
replace_all (action, "<Actions>/", "");
|
||||
|
||||
if (modifier_state == US2400Protocol::MODIFIER_SHIFT) {
|
||||
i->second.shift = action;
|
||||
}
|
||||
|
||||
if (modifier_state == 0) {
|
||||
i->second.plain = action;
|
||||
}
|
||||
|
||||
edited = true;
|
||||
|
||||
save ();
|
||||
}
|
||||
|
||||
string
|
||||
DeviceProfile::name_when_edited (string const& base)
|
||||
{
|
||||
return string_compose ("%1 %2", base, edited_indicator);
|
||||
}
|
||||
|
||||
string
|
||||
DeviceProfile::name() const
|
||||
{
|
||||
if (edited) {
|
||||
if (_name.find (edited_indicator) == string::npos) {
|
||||
/* modify name to included edited indicator */
|
||||
return name_when_edited (_name);
|
||||
} else {
|
||||
/* name already contains edited indicator */
|
||||
return _name;
|
||||
}
|
||||
} else {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DeviceProfile::set_path (const string& p)
|
||||
{
|
||||
_path = p;
|
||||
}
|
||||
|
||||
/* XXX copied from libs/ardour/utils.cc */
|
||||
|
||||
static string
|
||||
legalize_for_path (const string& str)
|
||||
{
|
||||
string::size_type pos;
|
||||
string illegal_chars = "/\\"; /* DOS, POSIX. Yes, we're going to ignore HFS */
|
||||
string legal;
|
||||
|
||||
legal = str;
|
||||
pos = 0;
|
||||
|
||||
while ((pos = legal.find_first_of (illegal_chars, pos)) != string::npos) {
|
||||
legal.replace (pos, 1, "_");
|
||||
pos += 1;
|
||||
}
|
||||
|
||||
return string (legal);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DeviceProfile::save ()
|
||||
{
|
||||
std::string fullpath = user_devprofile_directory();
|
||||
|
||||
if (g_mkdir_with_parents (fullpath.c_str(), 0755) < 0) {
|
||||
error << string_compose(_("Session: cannot create user MCP profile folder \"%1\" (%2)"), fullpath, strerror (errno)) << endmsg;
|
||||
return;
|
||||
}
|
||||
|
||||
fullpath = Glib::build_filename (fullpath, string_compose ("%1%2", legalize_for_path (name()), devprofile_suffix));
|
||||
|
||||
XMLTree tree;
|
||||
tree.set_root (&get_state());
|
||||
|
||||
if (!tree.write (fullpath)) {
|
||||
error << string_compose ("MCP profile not saved to %1", fullpath) << endmsg;
|
||||
}
|
||||
}
|
||||
80
libs/surfaces/us2400/device_profile.h
Normal file
80
libs/surfaces/us2400/device_profile.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_us2400_control_protocol_device_profile_h__
|
||||
#define __ardour_us2400_control_protocol_device_profile_h__
|
||||
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "button.h"
|
||||
|
||||
class XMLNode;
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
class DeviceProfile
|
||||
{
|
||||
public:
|
||||
DeviceProfile (const std::string& name = "");
|
||||
~DeviceProfile();
|
||||
|
||||
std::string get_button_action (Button::ID, int modifier_state) const;
|
||||
void set_button_action (Button::ID, int modifier_state, const std::string&);
|
||||
|
||||
std::string name() const;
|
||||
void set_path (const std::string&);
|
||||
|
||||
static void reload_device_profiles ();
|
||||
static std::map<std::string,DeviceProfile> device_profiles;
|
||||
static std::string name_when_edited (std::string const& name);
|
||||
static const std::string default_profile_name;
|
||||
|
||||
private:
|
||||
struct ButtonActions {
|
||||
std::string plain;
|
||||
std::string control;
|
||||
std::string shift;
|
||||
std::string option;
|
||||
std::string cmdalt;
|
||||
std::string shiftcontrol;
|
||||
};
|
||||
|
||||
typedef std::map<Button::ID,ButtonActions> ButtonActionMap;
|
||||
|
||||
std::string _name;
|
||||
std::string _path;
|
||||
ButtonActionMap _button_map;
|
||||
bool edited;
|
||||
|
||||
static const std::string edited_indicator;
|
||||
|
||||
int set_state (const XMLNode&, int version);
|
||||
XMLNode& get_state () const;
|
||||
|
||||
void save ();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ardour_us2400_control_protocol_device_profile_h__ */
|
||||
70
libs/surfaces/us2400/fader.cc
Normal file
70
libs/surfaces/us2400/fader.cc
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
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 <cmath>
|
||||
|
||||
#include "pbd/compose.h"
|
||||
|
||||
#include "ardour/debug.h"
|
||||
|
||||
#include "fader.h"
|
||||
#include "surface.h"
|
||||
#include "control_group.h"
|
||||
#include "us2400_control_protocol.h"
|
||||
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
using namespace PBD;
|
||||
|
||||
Control*
|
||||
Fader::factory (Surface& surface, int id, const char* name, Group& group)
|
||||
{
|
||||
Fader* f = new Fader (id, name, group);
|
||||
|
||||
surface.faders[id] = f;
|
||||
surface.controls.push_back (f);
|
||||
group.add (*f);
|
||||
return f;
|
||||
}
|
||||
|
||||
MidiByteArray
|
||||
Fader::set_position (float normalized)
|
||||
{
|
||||
position = normalized;
|
||||
return update_message ();
|
||||
}
|
||||
|
||||
MidiByteArray
|
||||
Fader::update_message ()
|
||||
{
|
||||
int posi = lrintf (16384.0 * position);
|
||||
|
||||
if (posi == last_update_position) {
|
||||
if (posi == llast_update_position) {
|
||||
return MidiByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
llast_update_position = last_update_position;
|
||||
last_update_position = posi;
|
||||
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("generate fader message for position %1 (%2)\n", position, posi));
|
||||
return MidiByteArray (3, 0xe0 + id(), posi & 0x7f, posi >> 7);
|
||||
}
|
||||
38
libs/surfaces/us2400/fader.h
Normal file
38
libs/surfaces/us2400/fader.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef __ardour_us2400_control_protocol_fader_h__
|
||||
#define __ardour_us2400_control_protocol_fader_h__
|
||||
|
||||
#include "controls.h"
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
class Fader : public Control
|
||||
{
|
||||
public:
|
||||
|
||||
Fader (int id, std::string name, Group & group)
|
||||
: Control (id, name, group)
|
||||
, position (0.0)
|
||||
, last_update_position (-1)
|
||||
, llast_update_position (-1)
|
||||
{
|
||||
}
|
||||
|
||||
MidiByteArray set_position (float);
|
||||
MidiByteArray zero() { return set_position (0.0); }
|
||||
|
||||
MidiByteArray update_message ();
|
||||
|
||||
static Control* factory (Surface&, int id, const char*, Group&);
|
||||
|
||||
private:
|
||||
float position;
|
||||
int last_update_position;
|
||||
int llast_update_position;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
824
libs/surfaces/us2400/gui.cc
Normal file
824
libs/surfaces/us2400/gui.cc
Normal file
@@ -0,0 +1,824 @@
|
||||
/*
|
||||
Copyright (C) 2010 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
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 <gtkmm/comboboxtext.h>
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/spinbutton.h>
|
||||
#include <gtkmm/table.h>
|
||||
#include <gtkmm/treeview.h>
|
||||
#include <gtkmm/liststore.h>
|
||||
#include <gtkmm/treestore.h>
|
||||
#include <gtkmm/notebook.h>
|
||||
#include <gtkmm/cellrenderercombo.h>
|
||||
#include <gtkmm/scale.h>
|
||||
#include <gtkmm/alignment.h>
|
||||
|
||||
#include "pbd/error.h"
|
||||
#include "pbd/unwind.h"
|
||||
#include "pbd/strsplit.h"
|
||||
#include "pbd/stacktrace.h"
|
||||
|
||||
#include "gtkmm2ext/actions.h"
|
||||
#include "gtkmm2ext/bindings.h"
|
||||
#include "gtkmm2ext/gui_thread.h"
|
||||
#include "gtkmm2ext/utils.h"
|
||||
|
||||
#include "ardour/audioengine.h"
|
||||
#include "ardour/port.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
|
||||
#include "us2400_control_protocol.h"
|
||||
#include "device_info.h"
|
||||
#include "gui.h"
|
||||
#include "surface.h"
|
||||
#include "surface_port.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace Gtk;
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
void*
|
||||
US2400Protocol::get_gui () const
|
||||
{
|
||||
if (!_gui) {
|
||||
const_cast<US2400Protocol*>(this)->build_gui ();
|
||||
}
|
||||
static_cast<Gtk::Notebook*>(_gui)->show_all();
|
||||
return _gui;
|
||||
}
|
||||
|
||||
void
|
||||
US2400Protocol::tear_down_gui ()
|
||||
{
|
||||
if (_gui) {
|
||||
Gtk::Widget *w = static_cast<Gtk::Widget*>(_gui)->get_parent();
|
||||
if (w) {
|
||||
w->hide();
|
||||
delete w;
|
||||
}
|
||||
}
|
||||
delete (US2400ProtocolGUI*) _gui;
|
||||
_gui = 0;
|
||||
}
|
||||
|
||||
void
|
||||
US2400Protocol::build_gui ()
|
||||
{
|
||||
_gui = (void *) new US2400ProtocolGUI (*this);
|
||||
}
|
||||
|
||||
US2400ProtocolGUI::US2400ProtocolGUI (US2400Protocol& p)
|
||||
: _cp (p)
|
||||
, table (2, 9)
|
||||
, _device_dependent_widget (0)
|
||||
, _ignore_profile_changed (false)
|
||||
, ignore_active_change (false)
|
||||
{
|
||||
Gtk::Label* l;
|
||||
Gtk::Alignment* align;
|
||||
int row = 0;
|
||||
|
||||
set_border_width (12);
|
||||
|
||||
table.set_row_spacings (4);
|
||||
table.set_col_spacings (6);
|
||||
table.set_border_width (12);
|
||||
table.set_homogeneous (false);
|
||||
|
||||
_cp.DeviceChanged.connect (device_change_connection, invalidator (*this), boost::bind (&US2400ProtocolGUI::device_changed, this), gui_context());
|
||||
_cp.ConnectionChange.connect (connection_change_connection, invalidator (*this), boost::bind (&US2400ProtocolGUI::connection_handler, this), gui_context());
|
||||
|
||||
/* device-dependent part */
|
||||
|
||||
device_dependent_row = row;
|
||||
|
||||
if (_device_dependent_widget) {
|
||||
table.remove (*_device_dependent_widget);
|
||||
_device_dependent_widget = 0;
|
||||
}
|
||||
|
||||
_device_dependent_widget = device_dependent_widget ();
|
||||
table.attach (*_device_dependent_widget, 0, 12, row, row+1, AttachOptions(0), AttachOptions(0), 0, 0);
|
||||
row++;
|
||||
|
||||
/* back to the boilerplate */
|
||||
|
||||
vector<string> profiles;
|
||||
|
||||
for (std::map<std::string,DeviceProfile>::iterator i = DeviceProfile::device_profiles.begin(); i != DeviceProfile::device_profiles.end(); ++i) {
|
||||
cerr << "add discovered profile " << i->first << endl;
|
||||
profiles.push_back (i->first);
|
||||
}
|
||||
Gtkmm2ext::set_popdown_strings (_profile_combo, profiles);
|
||||
cerr << "set active profile from " << p.device_profile().name() << endl;
|
||||
_profile_combo.set_active_text (p.device_profile().name());
|
||||
_profile_combo.signal_changed().connect (sigc::mem_fun (*this, &US2400ProtocolGUI::profile_combo_changed));
|
||||
|
||||
append_page (table, _("Device Setup"));
|
||||
table.show_all();
|
||||
|
||||
/* function key editor */
|
||||
|
||||
VBox* fkey_packer = manage (new VBox);
|
||||
HBox* profile_packer = manage (new HBox);
|
||||
HBox* observation_packer = manage (new HBox);
|
||||
|
||||
l = manage (new Gtk::Label (_("Profile/Settings:")));
|
||||
profile_packer->pack_start (*l, false, false);
|
||||
profile_packer->pack_start (_profile_combo, true, true);
|
||||
profile_packer->set_spacing (12);
|
||||
profile_packer->set_border_width (12);
|
||||
|
||||
fkey_packer->pack_start (*profile_packer, false, false);
|
||||
fkey_packer->pack_start (function_key_scroller, true, true);
|
||||
fkey_packer->pack_start (*observation_packer, false, false);
|
||||
fkey_packer->set_spacing (12);
|
||||
function_key_scroller.property_shadow_type() = Gtk::SHADOW_NONE;
|
||||
function_key_scroller.add (function_key_editor);
|
||||
append_page (*fkey_packer, _("Function Keys"));
|
||||
|
||||
build_available_action_menu ();
|
||||
build_function_key_editor ();
|
||||
refresh_function_key_editor ();
|
||||
fkey_packer->show_all();
|
||||
}
|
||||
|
||||
void
|
||||
US2400ProtocolGUI::connection_handler ()
|
||||
{
|
||||
/* ignore all changes to combobox active strings here, because we're
|
||||
updating them to match a new ("external") reality - we were called
|
||||
because port connections have changed.
|
||||
*/
|
||||
|
||||
PBD::Unwinder<bool> ici (ignore_active_change, true);
|
||||
|
||||
vector<Gtk::ComboBox*>::iterator ic;
|
||||
vector<Gtk::ComboBox*>::iterator oc;
|
||||
|
||||
vector<string> midi_inputs;
|
||||
vector<string> midi_outputs;
|
||||
|
||||
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsTerminal), midi_inputs);
|
||||
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsTerminal), midi_outputs);
|
||||
|
||||
for (ic = input_combos.begin(), oc = output_combos.begin(); ic != input_combos.end() && oc != output_combos.end(); ++ic, ++oc) {
|
||||
|
||||
boost::shared_ptr<Surface> surface = _cp.get_surface_by_raw_pointer ((*ic)->get_data ("surface"));
|
||||
|
||||
if (surface) {
|
||||
update_port_combos (midi_inputs, midi_outputs, *ic, *oc, surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
US2400ProtocolGUI::update_port_combos (vector<string> const& midi_inputs, vector<string> const& midi_outputs,
|
||||
Gtk::ComboBox* input_combo,
|
||||
Gtk::ComboBox* output_combo,
|
||||
boost::shared_ptr<Surface> surface)
|
||||
{
|
||||
Glib::RefPtr<Gtk::ListStore> input = build_midi_port_list (midi_inputs, true);
|
||||
Glib::RefPtr<Gtk::ListStore> output = build_midi_port_list (midi_outputs, false);
|
||||
bool input_found = false;
|
||||
bool output_found = false;
|
||||
int n;
|
||||
|
||||
input_combo->set_model (input);
|
||||
output_combo->set_model (output);
|
||||
|
||||
Gtk::TreeModel::Children children = input->children();
|
||||
Gtk::TreeModel::Children::iterator i;
|
||||
i = children.begin();
|
||||
++i; /* skip "Disconnected" */
|
||||
|
||||
|
||||
for (n = 1; i != children.end(); ++i, ++n) {
|
||||
string port_name = (*i)[midi_port_columns.full_name];
|
||||
if (surface->port().input().connected_to (port_name)) {
|
||||
input_combo->set_active (n);
|
||||
input_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!input_found) {
|
||||
input_combo->set_active (0); /* disconnected */
|
||||
}
|
||||
|
||||
children = output->children();
|
||||
i = children.begin();
|
||||
++i; /* skip "Disconnected" */
|
||||
|
||||
for (n = 1; i != children.end(); ++i, ++n) {
|
||||
string port_name = (*i)[midi_port_columns.full_name];
|
||||
if (surface->port().output().connected_to (port_name)) {
|
||||
output_combo->set_active (n);
|
||||
output_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!output_found) {
|
||||
output_combo->set_active (0); /* disconnected */
|
||||
}
|
||||
}
|
||||
|
||||
Gtk::Widget*
|
||||
US2400ProtocolGUI::device_dependent_widget ()
|
||||
{
|
||||
Gtk::Table* dd_table;
|
||||
Gtk::Label* l;
|
||||
int row = 0;
|
||||
|
||||
uint32_t n_surfaces = 1 + _cp.device_info().extenders();
|
||||
uint32_t main_pos = _cp.device_info().master_position();
|
||||
|
||||
dd_table = Gtk::manage (new Gtk::Table (2, n_surfaces));
|
||||
dd_table->set_row_spacings (4);
|
||||
dd_table->set_col_spacings (6);
|
||||
dd_table->set_border_width (12);
|
||||
|
||||
vector<string> midi_inputs;
|
||||
vector<string> midi_outputs;
|
||||
|
||||
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsOutput|ARDOUR::IsPhysical), midi_inputs);
|
||||
ARDOUR::AudioEngine::instance()->get_ports ("", ARDOUR::DataType::MIDI, ARDOUR::PortFlags (ARDOUR::IsInput|ARDOUR::IsPhysical), midi_outputs);
|
||||
|
||||
input_combos.clear ();
|
||||
output_combos.clear ();
|
||||
|
||||
int portcount = n_surfaces;
|
||||
|
||||
for (uint32_t n = 0; n < portcount; ++n) {
|
||||
|
||||
boost::shared_ptr<Surface> surface = _cp.nth_surface (n);
|
||||
|
||||
if (!surface) {
|
||||
PBD::fatal << string_compose (_("programming error: %1\n"), string_compose ("n=%1 surface not found!", n)) << endmsg;
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
Gtk::ComboBox* input_combo = manage (new Gtk::ComboBox);
|
||||
Gtk::ComboBox* output_combo = manage (new Gtk::ComboBox);
|
||||
|
||||
update_port_combos (midi_inputs, midi_outputs, input_combo, output_combo, surface);
|
||||
|
||||
input_combo->pack_start (midi_port_columns.short_name);
|
||||
input_combo->set_data ("surface", surface.get());
|
||||
input_combos.push_back (input_combo);
|
||||
output_combo->pack_start (midi_port_columns.short_name);
|
||||
output_combo->set_data ("surface", surface.get());
|
||||
output_combos.push_back (output_combo);
|
||||
|
||||
boost::weak_ptr<Surface> ws (surface);
|
||||
input_combo->signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &US2400ProtocolGUI::active_port_changed), input_combo, ws, true));
|
||||
output_combo->signal_changed().connect (sigc::bind (sigc::mem_fun (*this, &US2400ProtocolGUI::active_port_changed), output_combo, ws, false));
|
||||
|
||||
string send_string;
|
||||
string receive_string;
|
||||
|
||||
//port 1,2,3 are faders & pan knobs. like mackie MCU
|
||||
//port 4 is the joystick
|
||||
//port 5 sends "chan" knobs (24 of them )
|
||||
//port 6 --- ??? ( could be send to knobs... ? )
|
||||
|
||||
send_string = string_compose(_("US-2400 send port #%1 (faders %2 to %3):"), n + 1, n*8+1, n*8+8);
|
||||
receive_string = string_compose(_("US-2400 receive port #%1 (faders %2 to %3):"), n + 1, n*8+1, n*8+8);
|
||||
if (n==3) {
|
||||
send_string = string_compose(_("US-2400 send port #%1 (joystick):"), n + 1);
|
||||
receive_string = string_compose(_("US-2400 receive port #%1 (joystick):"), n + 1);
|
||||
}
|
||||
|
||||
l = manage (new Gtk::Label (send_string));
|
||||
l->set_alignment (1.0, 0.5);
|
||||
dd_table->attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
|
||||
dd_table->attach (*input_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
|
||||
row++;
|
||||
|
||||
l = manage (new Gtk::Label (receive_string));
|
||||
l->set_alignment (1.0, 0.5);
|
||||
dd_table->attach (*l, 0, 1, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
|
||||
dd_table->attach (*output_combo, 1, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0), 0, 0);
|
||||
row++;
|
||||
}
|
||||
|
||||
row++;
|
||||
|
||||
l = manage (new Gtk::Label ("US-2400 Port #5 is reserved for use as a generic USB device. (click the CHAN button to activate)"));
|
||||
l->set_alignment (1.0, 0.5);
|
||||
dd_table->attach (*l, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
|
||||
row++;
|
||||
row++;
|
||||
|
||||
l = manage (new Gtk::Label ("US-2400 Port #6 is unused."));
|
||||
l->set_alignment (1.0, 0.5);
|
||||
dd_table->attach (*l, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
|
||||
row++;
|
||||
row++;
|
||||
|
||||
l = manage (new Gtk::Label ("NOTE: you must select mode 4 on the US-2400 unit."));
|
||||
l->set_alignment (1.0, 0.5);
|
||||
dd_table->attach (*l, 0, 2, row, row+1, AttachOptions(FILL|EXPAND), AttachOptions(0));
|
||||
row++;
|
||||
|
||||
|
||||
return dd_table;
|
||||
}
|
||||
|
||||
CellRendererCombo*
|
||||
US2400ProtocolGUI::make_action_renderer (Glib::RefPtr<TreeStore> model, Gtk::TreeModelColumnBase column)
|
||||
{
|
||||
CellRendererCombo* renderer = manage (new CellRendererCombo);
|
||||
renderer->property_model() = model;
|
||||
renderer->property_editable() = true;
|
||||
renderer->property_text_column() = 0;
|
||||
renderer->property_has_entry() = false;
|
||||
renderer->signal_edited().connect (sigc::bind (sigc::mem_fun(*this, &US2400ProtocolGUI::action_changed), column));
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
void
|
||||
US2400ProtocolGUI::build_available_action_menu ()
|
||||
{
|
||||
/* build a model of all available actions (needs to be tree structured
|
||||
* more)
|
||||
*/
|
||||
|
||||
available_action_model = TreeStore::create (available_action_columns);
|
||||
|
||||
vector<string> paths;
|
||||
vector<string> labels;
|
||||
vector<string> tooltips;
|
||||
vector<string> keys;
|
||||
vector<Glib::RefPtr<Gtk::Action> > actions;
|
||||
|
||||
typedef std::map<string,TreeIter> NodeMap;
|
||||
NodeMap nodes;
|
||||
NodeMap::iterator r;
|
||||
|
||||
Gtkmm2ext::ActionMap::get_all_actions (paths, labels, tooltips, keys, actions);
|
||||
|
||||
vector<string>::iterator k;
|
||||
vector<string>::iterator p;
|
||||
vector<string>::iterator t;
|
||||
vector<string>::iterator l;
|
||||
|
||||
available_action_model->clear ();
|
||||
|
||||
/* Because there are button bindings built in that are not
|
||||
in the key binding map, there needs to be a way to undo
|
||||
a profile edit.
|
||||
*/
|
||||
TreeIter rowp;
|
||||
TreeModel::Row parent;
|
||||
rowp = available_action_model->append();
|
||||
parent = *(rowp);
|
||||
parent[available_action_columns.name] = _("Remove Binding");
|
||||
|
||||
/* Key aliasing */
|
||||
|
||||
rowp = available_action_model->append();
|
||||
parent = *(rowp);
|
||||
parent[available_action_columns.name] = _("Shift");
|
||||
rowp = available_action_model->append();
|
||||
parent = *(rowp);
|
||||
parent[available_action_columns.name] = _("Control");
|
||||
rowp = available_action_model->append();
|
||||
parent = *(rowp);
|
||||
parent[available_action_columns.name] = _("Option");
|
||||
rowp = available_action_model->append();
|
||||
parent = *(rowp);
|
||||
parent[available_action_columns.name] = _("CmdAlt");
|
||||
|
||||
for (l = labels.begin(), k = keys.begin(), p = paths.begin(), t = tooltips.begin(); l != labels.end(); ++k, ++p, ++t, ++l) {
|
||||
|
||||
TreeModel::Row row;
|
||||
vector<string> parts;
|
||||
|
||||
parts.clear ();
|
||||
|
||||
split (*p, parts, '/');
|
||||
|
||||
if (parts.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//kinda kludgy way to avoid displaying menu items as mappable
|
||||
if ( parts[1] == _("Main_menu") )
|
||||
continue;
|
||||
if ( parts[1] == _("JACK") )
|
||||
continue;
|
||||
if ( parts[1] == _("redirectmenu") )
|
||||
continue;
|
||||
if ( parts[1] == _("Editor_menus") )
|
||||
continue;
|
||||
if ( parts[1] == _("RegionList") )
|
||||
continue;
|
||||
if ( parts[1] == _("ProcessorMenu") )
|
||||
continue;
|
||||
|
||||
if ((r = nodes.find (parts[1])) == nodes.end()) {
|
||||
|
||||
/* top level is missing */
|
||||
|
||||
TreeIter rowp;
|
||||
TreeModel::Row parent;
|
||||
rowp = available_action_model->append();
|
||||
nodes[parts[1]] = rowp;
|
||||
parent = *(rowp);
|
||||
parent[available_action_columns.name] = parts[1];
|
||||
|
||||
row = *(available_action_model->append (parent.children()));
|
||||
|
||||
} else {
|
||||
|
||||
row = *(available_action_model->append ((*r->second)->children()));
|
||||
|
||||
}
|
||||
|
||||
/* add this action */
|
||||
|
||||
if (l->empty ()) {
|
||||
row[available_action_columns.name] = *t;
|
||||
action_map[*t] = *p;
|
||||
} else {
|
||||
row[available_action_columns.name] = *l;
|
||||
action_map[*l] = *p;
|
||||
}
|
||||
|
||||
row[available_action_columns.path] = (*p);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
US2400ProtocolGUI::build_function_key_editor ()
|
||||
{
|
||||
function_key_editor.append_column (_("Key"), function_key_columns.name);
|
||||
|
||||
TreeViewColumn* col;
|
||||
CellRendererCombo* renderer;
|
||||
|
||||
renderer = make_action_renderer (available_action_model, function_key_columns.plain);
|
||||
col = manage (new TreeViewColumn (_("Plain"), *renderer));
|
||||
col->add_attribute (renderer->property_text(), function_key_columns.plain);
|
||||
function_key_editor.append_column (*col);
|
||||
|
||||
renderer = make_action_renderer (available_action_model, function_key_columns.shift);
|
||||
col = manage (new TreeViewColumn (_("Shift"), *renderer));
|
||||
col->add_attribute (renderer->property_text(), function_key_columns.shift);
|
||||
function_key_editor.append_column (*col);
|
||||
|
||||
/*
|
||||
* renderer = make_action_renderer (available_action_model, function_key_columns.control);
|
||||
col = manage (new TreeViewColumn (_("Control"), *renderer));
|
||||
col->add_attribute (renderer->property_text(), function_key_columns.control);
|
||||
function_key_editor.append_column (*col);
|
||||
|
||||
renderer = make_action_renderer (available_action_model, function_key_columns.option);
|
||||
col = manage (new TreeViewColumn (_("Option"), *renderer));
|
||||
col->add_attribute (renderer->property_text(), function_key_columns.option);
|
||||
function_key_editor.append_column (*col);
|
||||
|
||||
renderer = make_action_renderer (available_action_model, function_key_columns.cmdalt);
|
||||
col = manage (new TreeViewColumn (_("Cmd/Alt"), *renderer));
|
||||
col->add_attribute (renderer->property_text(), function_key_columns.cmdalt);
|
||||
function_key_editor.append_column (*col);
|
||||
|
||||
renderer = make_action_renderer (available_action_model, function_key_columns.shiftcontrol);
|
||||
col = manage (new TreeViewColumn (_("Shift+Control"), *renderer));
|
||||
col->add_attribute (renderer->property_text(), function_key_columns.shiftcontrol);
|
||||
function_key_editor.append_column (*col);
|
||||
*/
|
||||
|
||||
function_key_model = ListStore::create (function_key_columns);
|
||||
function_key_editor.set_model (function_key_model);
|
||||
}
|
||||
|
||||
void
|
||||
US2400ProtocolGUI::refresh_function_key_editor ()
|
||||
{
|
||||
function_key_editor.set_model (Glib::RefPtr<TreeModel>());
|
||||
function_key_model->clear ();
|
||||
|
||||
/* now fill with data */
|
||||
|
||||
TreeModel::Row row;
|
||||
DeviceProfile dp (_cp.device_profile());
|
||||
DeviceInfo di;
|
||||
|
||||
for (int n = 0; n < US2400::Button::FinalGlobalButton; ++n) {
|
||||
|
||||
US2400::Button::ID bid = (US2400::Button::ID) n;
|
||||
|
||||
row = *(function_key_model->append());
|
||||
if (di.global_buttons().find (bid) == di.global_buttons().end()) {
|
||||
row[function_key_columns.name] = US2400::Button::id_to_name (bid);
|
||||
} else {
|
||||
row[function_key_columns.name] = di.get_global_button_name (bid) + "*";
|
||||
}
|
||||
row[function_key_columns.id] = bid;
|
||||
|
||||
Glib::RefPtr<Gtk::Action> act;
|
||||
string action;
|
||||
const string defstring = "\u2022";
|
||||
|
||||
/* We only allow plain bindings for Fn keys. All others are
|
||||
* reserved for hard-coded actions.
|
||||
*/
|
||||
|
||||
if (bid >= US2400::Button::F1 && bid <= US2400::Button::F6) {
|
||||
|
||||
action = dp.get_button_action (bid, 0);
|
||||
if (action.empty()) {
|
||||
row[function_key_columns.plain] = defstring;
|
||||
} else {
|
||||
if (action.find ('/') == string::npos) {
|
||||
/* Probably a key alias */
|
||||
row[function_key_columns.plain] = action;
|
||||
} else {
|
||||
|
||||
act = ActionManager::get_action (action.c_str());
|
||||
if (act) {
|
||||
row[function_key_columns.plain] = act->get_label();
|
||||
} else {
|
||||
row[function_key_columns.plain] = defstring;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//~ /* We only allow plain bindings for Fn keys. All others are
|
||||
//~ * reserved for hard-coded actions.
|
||||
//~ */
|
||||
//~
|
||||
//~ if (bid >= US2400::Button::F1 && bid <= US2400::Button::F8) {
|
||||
//~
|
||||
//~ action = dp.get_button_action (bid, US2400Protocol::MODIFIER_SHIFT);
|
||||
//~ if (action.empty()) {
|
||||
//~ row[function_key_columns.shift] = defstring;
|
||||
//~ } else {
|
||||
//~ if (action.find ('/') == string::npos) {
|
||||
//~ /* Probably a key alias */
|
||||
//~ row[function_key_columns.shift] = action;
|
||||
//~ } else {
|
||||
//~ act = ActionManager::get_action (action.c_str());
|
||||
//~ if (act) {
|
||||
//~ row[function_key_columns.shift] = act->get_label();
|
||||
//~ } else {
|
||||
//~ row[function_key_columns.shift] = defstring;
|
||||
//~ }
|
||||
//~ }
|
||||
//~ }
|
||||
//~ }
|
||||
|
||||
//~ action = dp.get_button_action (bid, US2400Protocol::MODIFIER_CONTROL);
|
||||
//~ if (action.empty()) {
|
||||
//~ row[function_key_columns.control] = defstring;
|
||||
//~ } else {
|
||||
//~ if (action.find ('/') == string::npos) {
|
||||
//~ /* Probably a key alias */
|
||||
//~ row[function_key_columns.control] = action;
|
||||
//~ } else {
|
||||
//~ act = ActionManager::get_action (action.c_str());
|
||||
//~ if (act) {
|
||||
//~ row[function_key_columns.control] = act->get_label();
|
||||
//~ } else {
|
||||
//~ row[function_key_columns.control] = defstring;
|
||||
//~ }
|
||||
//~ }
|
||||
//~ }
|
||||
//~
|
||||
//~ action = dp.get_button_action (bid, US2400Protocol::MODIFIER_OPTION);
|
||||
//~ if (action.empty()) {
|
||||
//~ row[function_key_columns.option] = defstring;
|
||||
//~ } else {
|
||||
//~ if (action.find ('/') == string::npos) {
|
||||
//~ /* Probably a key alias */
|
||||
//~ row[function_key_columns.option] = action;
|
||||
//~ } else {
|
||||
//~ act = ActionManager::get_action (action.c_str());
|
||||
//~ if (act) {
|
||||
//~ row[function_key_columns.option] = act->get_label();
|
||||
//~ } else {
|
||||
//~ row[function_key_columns.option] = defstring;
|
||||
//~ }
|
||||
//~ }
|
||||
//~ }
|
||||
//~
|
||||
//~ action = dp.get_button_action (bid, US2400Protocol::MODIFIER_CMDALT);
|
||||
//~ if (action.empty()) {
|
||||
//~ row[function_key_columns.cmdalt] = defstring;
|
||||
//~ } else {
|
||||
//~ if (action.find ('/') == string::npos) {
|
||||
//~ /* Probably a key alias */
|
||||
//~ row[function_key_columns.cmdalt] = action;
|
||||
//~ } else {
|
||||
//~ act = ActionManager::get_action (action.c_str());
|
||||
//~ if (act) {
|
||||
//~ row[function_key_columns.cmdalt] = act->get_label();
|
||||
//~ } else {
|
||||
//~ row[function_key_columns.cmdalt] = defstring;
|
||||
//~ }
|
||||
//~ }
|
||||
//~ }
|
||||
//~
|
||||
//~ action = dp.get_button_action (bid, (US2400Protocol::MODIFIER_SHIFT|US2400Protocol::MODIFIER_CONTROL));
|
||||
//~ if (action.empty()) {
|
||||
//~ row[function_key_columns.shiftcontrol] = defstring;
|
||||
//~ } else {
|
||||
//~ act = ActionManager::get_action (action.c_str());
|
||||
//~ if (act) {
|
||||
//~ row[function_key_columns.shiftcontrol] = act->get_label();
|
||||
//~ } else {
|
||||
//~ row[function_key_columns.shiftcontrol] = defstring;
|
||||
//~ }
|
||||
//~ }
|
||||
}
|
||||
|
||||
function_key_editor.set_model (function_key_model);
|
||||
}
|
||||
|
||||
void
|
||||
US2400ProtocolGUI::action_changed (const Glib::ustring &sPath, const Glib::ustring &text, TreeModelColumnBase col)
|
||||
{
|
||||
// Remove Binding is not in the action map but still valid
|
||||
bool remove (false);
|
||||
if ( text == "Remove Binding") {
|
||||
remove = true;
|
||||
}
|
||||
Gtk::TreePath path(sPath);
|
||||
Gtk::TreeModel::iterator row = function_key_model->get_iter(path);
|
||||
|
||||
if (row) {
|
||||
|
||||
std::map<std::string,std::string>::iterator i = action_map.find (text);
|
||||
|
||||
if (i == action_map.end()) {
|
||||
if (!remove) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (i->second.c_str());
|
||||
|
||||
if (act || remove) {
|
||||
/* update visible text, using string supplied by
|
||||
available action model so that it matches and is found
|
||||
within the model.
|
||||
*/
|
||||
if (remove) {
|
||||
Glib::ustring dot = "\u2022";
|
||||
(*row).set_value (col.index(), dot);
|
||||
} else {
|
||||
(*row).set_value (col.index(), text);
|
||||
}
|
||||
|
||||
/* update the current DeviceProfile, using the full
|
||||
* path
|
||||
*/
|
||||
|
||||
int modifier;
|
||||
|
||||
switch (col.index()) {
|
||||
case 3:
|
||||
modifier = US2400Protocol::MODIFIER_SHIFT;
|
||||
break;
|
||||
case 4:
|
||||
modifier = US2400Protocol::MODIFIER_CONTROL;
|
||||
break;
|
||||
case 5:
|
||||
modifier = US2400Protocol::MODIFIER_OPTION;
|
||||
break;
|
||||
case 6:
|
||||
modifier = US2400Protocol::MODIFIER_CMDALT;
|
||||
break;
|
||||
case 7:
|
||||
modifier = (US2400Protocol::MODIFIER_SHIFT|US2400Protocol::MODIFIER_CONTROL);
|
||||
break;
|
||||
default:
|
||||
modifier = 0;
|
||||
}
|
||||
|
||||
if (remove) {
|
||||
_cp.device_profile().set_button_action ((*row)[function_key_columns.id], modifier, "");
|
||||
} else {
|
||||
_cp.device_profile().set_button_action ((*row)[function_key_columns.id], modifier, i->second);
|
||||
}
|
||||
|
||||
_ignore_profile_changed = true;
|
||||
_profile_combo.set_active_text ( _cp.device_profile().name() );
|
||||
_ignore_profile_changed = false;
|
||||
|
||||
} else {
|
||||
std::cerr << "no such action\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
US2400ProtocolGUI::device_changed ()
|
||||
{
|
||||
if (_device_dependent_widget) {
|
||||
table.remove (*_device_dependent_widget);
|
||||
_device_dependent_widget = 0;
|
||||
}
|
||||
|
||||
_device_dependent_widget = device_dependent_widget ();
|
||||
_device_dependent_widget->show_all ();
|
||||
|
||||
table.attach (*_device_dependent_widget, 0, 12, device_dependent_row, device_dependent_row+1, AttachOptions(0), AttachOptions(0), 0, 0);
|
||||
}
|
||||
|
||||
void
|
||||
US2400ProtocolGUI::profile_combo_changed ()
|
||||
{
|
||||
if (!_ignore_profile_changed) {
|
||||
string profile = _profile_combo.get_active_text();
|
||||
|
||||
_cp.set_profile (profile);
|
||||
|
||||
refresh_function_key_editor ();
|
||||
}
|
||||
}
|
||||
|
||||
Glib::RefPtr<Gtk::ListStore>
|
||||
US2400ProtocolGUI::build_midi_port_list (vector<string> const & ports, bool for_input)
|
||||
{
|
||||
Glib::RefPtr<Gtk::ListStore> store = ListStore::create (midi_port_columns);
|
||||
TreeModel::Row row;
|
||||
|
||||
row = *store->append ();
|
||||
row[midi_port_columns.full_name] = string();
|
||||
row[midi_port_columns.short_name] = _("Disconnected");
|
||||
|
||||
for (vector<string>::const_iterator p = ports.begin(); p != ports.end(); ++p) {
|
||||
row = *store->append ();
|
||||
row[midi_port_columns.full_name] = *p;
|
||||
std::string pn = ARDOUR::AudioEngine::instance()->get_pretty_name_by_name (*p);
|
||||
if (pn.empty ()) {
|
||||
pn = (*p).substr ((*p).find (':') + 1);
|
||||
}
|
||||
row[midi_port_columns.short_name] = pn;
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
void
|
||||
US2400ProtocolGUI::active_port_changed (Gtk::ComboBox* combo, boost::weak_ptr<Surface> ws, bool for_input)
|
||||
{
|
||||
if (ignore_active_change) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<Surface> surface = ws.lock();
|
||||
|
||||
if (!surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
TreeModel::iterator active = combo->get_active ();
|
||||
string new_port = (*active)[midi_port_columns.full_name];
|
||||
|
||||
if (new_port.empty()) {
|
||||
if (for_input) {
|
||||
surface->port().input().disconnect_all ();
|
||||
} else {
|
||||
surface->port().output().disconnect_all ();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (for_input) {
|
||||
if (!surface->port().input().connected_to (new_port)) {
|
||||
surface->port().input().disconnect_all ();
|
||||
surface->port().input().connect (new_port);
|
||||
}
|
||||
} else {
|
||||
if (!surface->port().output().connected_to (new_port)) {
|
||||
surface->port().output().disconnect_all ();
|
||||
surface->port().output().connect (new_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
142
libs/surfaces/us2400/gui.h
Normal file
142
libs/surfaces/us2400/gui.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
Copyright (C) 2010-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 <vector>
|
||||
|
||||
#include <gtkmm/combobox.h>
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/spinbutton.h>
|
||||
#include <gtkmm/table.h>
|
||||
#include <gtkmm/treeview.h>
|
||||
#include <gtkmm/liststore.h>
|
||||
#include <gtkmm/notebook.h>
|
||||
#include <gtkmm/scrolledwindow.h>
|
||||
|
||||
namespace Gtk {
|
||||
class CellRendererCombo;
|
||||
}
|
||||
|
||||
#include "button.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
class US2400Protocol;
|
||||
|
||||
namespace US2400 {
|
||||
class Surface;
|
||||
}
|
||||
|
||||
class US2400ProtocolGUI : public Gtk::Notebook
|
||||
{
|
||||
public:
|
||||
US2400ProtocolGUI (US2400Protocol &);
|
||||
|
||||
private:
|
||||
US2400Protocol& _cp;
|
||||
Gtk::Table table;
|
||||
Gtk::ComboBoxText _profile_combo;
|
||||
|
||||
typedef std::vector<Gtk::ComboBox*> PortCombos;
|
||||
PortCombos input_combos;
|
||||
PortCombos output_combos;
|
||||
|
||||
struct MidiPortColumns : public Gtk::TreeModel::ColumnRecord {
|
||||
MidiPortColumns() {
|
||||
add (short_name);
|
||||
add (full_name);
|
||||
}
|
||||
Gtk::TreeModelColumn<std::string> short_name;
|
||||
Gtk::TreeModelColumn<std::string> full_name;
|
||||
};
|
||||
|
||||
struct AvailableActionColumns : public Gtk::TreeModel::ColumnRecord {
|
||||
AvailableActionColumns() {
|
||||
add (name);
|
||||
add (path);
|
||||
}
|
||||
Gtk::TreeModelColumn<std::string> name;
|
||||
Gtk::TreeModelColumn<std::string> path;
|
||||
};
|
||||
|
||||
struct FunctionKeyColumns : public Gtk::TreeModel::ColumnRecord {
|
||||
FunctionKeyColumns() {
|
||||
add (name);
|
||||
add (id);
|
||||
add (plain);
|
||||
add (shift);
|
||||
add (control);
|
||||
add (option);
|
||||
add (cmdalt);
|
||||
add (shiftcontrol);
|
||||
};
|
||||
Gtk::TreeModelColumn<std::string> name;
|
||||
Gtk::TreeModelColumn<US2400::Button::ID> id;
|
||||
Gtk::TreeModelColumn<std::string> plain;
|
||||
Gtk::TreeModelColumn<std::string> shift;
|
||||
Gtk::TreeModelColumn<std::string> control;
|
||||
Gtk::TreeModelColumn<std::string> option;
|
||||
Gtk::TreeModelColumn<std::string> cmdalt;
|
||||
Gtk::TreeModelColumn<std::string> shiftcontrol;
|
||||
};
|
||||
|
||||
AvailableActionColumns available_action_columns;
|
||||
FunctionKeyColumns function_key_columns;
|
||||
MidiPortColumns midi_port_columns;
|
||||
|
||||
Gtk::ScrolledWindow function_key_scroller;
|
||||
Gtk::TreeView function_key_editor;
|
||||
Glib::RefPtr<Gtk::ListStore> function_key_model;
|
||||
Glib::RefPtr<Gtk::TreeStore> available_action_model;
|
||||
|
||||
Glib::RefPtr<Gtk::ListStore> build_midi_port_list (bool for_input);
|
||||
|
||||
void build_available_action_menu ();
|
||||
void refresh_function_key_editor ();
|
||||
void build_function_key_editor ();
|
||||
void action_changed (const Glib::ustring &sPath, const Glib::ustring &text, Gtk::TreeModelColumnBase);
|
||||
Gtk::CellRendererCombo* make_action_renderer (Glib::RefPtr<Gtk::TreeStore> model, Gtk::TreeModelColumnBase);
|
||||
|
||||
void profile_combo_changed ();
|
||||
|
||||
std::map<std::string,std::string> action_map; // map from action names to paths
|
||||
|
||||
Gtk::Widget* device_dependent_widget ();
|
||||
Gtk::Widget* _device_dependent_widget;
|
||||
int device_dependent_row;
|
||||
|
||||
PBD::ScopedConnection device_change_connection;
|
||||
void device_changed ();
|
||||
|
||||
void update_port_combos (std::vector<std::string> const&, std::vector<std::string> const&,
|
||||
Gtk::ComboBox* input_combo,
|
||||
Gtk::ComboBox* output_combo,
|
||||
boost::shared_ptr<US2400::Surface> surface);
|
||||
|
||||
PBD::ScopedConnection connection_change_connection;
|
||||
void connection_handler ();
|
||||
|
||||
Glib::RefPtr<Gtk::ListStore> build_midi_port_list (std::vector<std::string> const & ports, bool for_input);
|
||||
bool _ignore_profile_changed;
|
||||
bool ignore_active_change;
|
||||
void active_port_changed (Gtk::ComboBox* combo, boost::weak_ptr<US2400::Surface> ws, bool for_input);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
102
libs/surfaces/us2400/interface.cc
Normal file
102
libs/surfaces/us2400/interface.cc
Normal file
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
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 <stdexcept>
|
||||
|
||||
#include "pbd/error.h"
|
||||
|
||||
#include "ardour/rc_configuration.h"
|
||||
|
||||
#include "control_protocol/control_protocol.h"
|
||||
#include "us2400_control_protocol.h"
|
||||
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace std;
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
static ControlProtocol*
|
||||
new_us2400_protocol (ControlProtocolDescriptor*, Session* s)
|
||||
{
|
||||
US2400Protocol* mcp = 0;
|
||||
|
||||
try {
|
||||
mcp = new US2400Protocol (*s);
|
||||
/* do not set active here - wait for set_state() */
|
||||
}
|
||||
catch (exception & e) {
|
||||
error << "Error instantiating US-2400: " << e.what() << endmsg;
|
||||
delete mcp;
|
||||
mcp = 0;
|
||||
}
|
||||
|
||||
return mcp;
|
||||
}
|
||||
|
||||
static void
|
||||
delete_us2400_protocol (ControlProtocolDescriptor*, ControlProtocol* cp)
|
||||
{
|
||||
try
|
||||
{
|
||||
delete cp;
|
||||
}
|
||||
catch ( exception & e )
|
||||
{
|
||||
cout << "Exception caught trying to destroy US-2400: " << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
This is called on startup to check whether the lib should be loaded.
|
||||
|
||||
So anything that can be changed in the UI should not be used here to
|
||||
prevent loading of the lib.
|
||||
*/
|
||||
static bool
|
||||
probe_us2400_protocol (ControlProtocolDescriptor*)
|
||||
{
|
||||
return US2400Protocol::probe();
|
||||
}
|
||||
|
||||
static void*
|
||||
us2400_request_buffer_factory (uint32_t num_requests)
|
||||
{
|
||||
return US2400Protocol::request_factory (num_requests);
|
||||
}
|
||||
|
||||
// Field names commented out by JE - 06-01-2010
|
||||
static ControlProtocolDescriptor us2400_descriptor = {
|
||||
/*name : */ "Tascam US-2400",
|
||||
/*id : */ "uri://ardour.org/surfaces/us2400:0",
|
||||
/*ptr : */ 0,
|
||||
/*module : */ 0,
|
||||
/*mandatory : */ 0,
|
||||
// actually, the surface does support feedback, but all this
|
||||
// flag does is show a submenu on the UI, which is useless for the mackie
|
||||
// because feedback is always on. In any case, who'd want to use the
|
||||
// mcu without the motorised sliders doing their thing?
|
||||
/*supports_feedback : */ false,
|
||||
/*probe : */ probe_us2400_protocol,
|
||||
/*initialize : */ new_us2400_protocol,
|
||||
/*destroy : */ delete_us2400_protocol,
|
||||
/*request_buffer_factory */ us2400_request_buffer_factory
|
||||
};
|
||||
|
||||
extern "C" ARDOURSURFACE_API ControlProtocolDescriptor* protocol_descriptor () { return &us2400_descriptor; }
|
||||
37
libs/surfaces/us2400/jog.cc
Normal file
37
libs/surfaces/us2400/jog.cc
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
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 "jog.h"
|
||||
#include "surface.h"
|
||||
#include "control_group.h"
|
||||
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
const int Jog::ID = 0x3c;
|
||||
|
||||
Control*
|
||||
Jog::factory (Surface& surface, int id, const char* name, Group& group)
|
||||
{
|
||||
Jog* j = new Jog (id, name, group);
|
||||
surface.pots[id] = j;
|
||||
surface.controls.push_back (j);
|
||||
group.add (*j);
|
||||
return j;
|
||||
}
|
||||
49
libs/surfaces/us2400/jog.h
Normal file
49
libs/surfaces/us2400/jog.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
|
||||
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_us2400_control_protocol_jog_h__
|
||||
#define __ardour_us2400_control_protocol_jog_h__
|
||||
|
||||
#include "controls.h"
|
||||
#include "pot.h"
|
||||
|
||||
namespace ArdourSurface {
|
||||
namespace US2400 {
|
||||
|
||||
class Jog : public Pot
|
||||
{
|
||||
public:
|
||||
static const int ID;
|
||||
|
||||
Jog (int id, std::string name, Group & group)
|
||||
: Pot (id, name, group)
|
||||
{
|
||||
}
|
||||
|
||||
MidiByteArray zero() { return MidiByteArray(); }
|
||||
|
||||
static Control* factory (Surface&, int id, const char*, Group&);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ardour_us2400_control_protocol_jog_h__ */
|
||||
70
libs/surfaces/us2400/jog_wheel.cc
Normal file
70
libs/surfaces/us2400/jog_wheel.cc
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
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 <cmath>
|
||||
|
||||
#include "ardour/session.h"
|
||||
|
||||
#include "jog_wheel.h"
|
||||
#include "us2400_control_protocol.h"
|
||||
#include "surface_port.h"
|
||||
#include "controls.h"
|
||||
#include "surface.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
JogWheel::JogWheel (US2400Protocol & mcp)
|
||||
: _mcp (mcp)
|
||||
, _mode (scroll)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
JogWheel::set_mode (Mode m)
|
||||
{
|
||||
_mode = m;
|
||||
}
|
||||
|
||||
void JogWheel::jog_event (float delta)
|
||||
{
|
||||
if (_mcp.zoom_mode()) {
|
||||
if (delta > 0) {
|
||||
for (unsigned int i = 0; i < fabs (delta); ++i) {
|
||||
_mcp.ZoomIn();
|
||||
}
|
||||
} else {
|
||||
for (unsigned int i = 0; i < fabs (delta); ++i) {
|
||||
_mcp.ZoomOut();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (_mode) {
|
||||
case scroll:
|
||||
_mcp.ScrollTimeline (delta/4.0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
37
libs/surfaces/us2400/jog_wheel.h
Normal file
37
libs/surfaces/us2400/jog_wheel.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef mackie_jog_wheel
|
||||
#define mackie_jog_wheel
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
#include <stack>
|
||||
#include <deque>
|
||||
#include <queue>
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
class US2400Protocol;
|
||||
|
||||
namespace US2400
|
||||
{
|
||||
|
||||
class JogWheel
|
||||
{
|
||||
public:
|
||||
enum Mode { scroll };
|
||||
|
||||
JogWheel (US2400Protocol & mcp);
|
||||
|
||||
/// As the wheel turns...
|
||||
void jog_event (float delta);
|
||||
void set_mode (Mode m);
|
||||
Mode mode() const { return _mode; }
|
||||
|
||||
private:
|
||||
US2400Protocol & _mcp;
|
||||
Mode _mode;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
75
libs/surfaces/us2400/led.cc
Normal file
75
libs/surfaces/us2400/led.cc
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
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 "led.h"
|
||||
#include "surface.h"
|
||||
#include "control_group.h"
|
||||
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
const int Led::FaderTouch = 0x70;
|
||||
const int Led::Timecode = 0x71;
|
||||
const int Led::Beats = 0x72;
|
||||
const int Led::RudeSolo = 0x73;
|
||||
const int Led::RelayClick = 0x74;
|
||||
|
||||
Control*
|
||||
Led::factory (Surface& surface, int id, const char* name, Group& group)
|
||||
{
|
||||
Led* l = new Led (id, name, group);
|
||||
surface.leds[id] = l;
|
||||
surface.controls.push_back (l);
|
||||
group.add (*l);
|
||||
return l;
|
||||
}
|
||||
|
||||
MidiByteArray
|
||||
Led::set_state (LedState new_state)
|
||||
{
|
||||
if (new_state == last_state) {
|
||||
if (new_state == llast_state) {
|
||||
return MidiByteArray ();
|
||||
}
|
||||
}
|
||||
llast_state = last_state;
|
||||
last_state = new_state;
|
||||
|
||||
|
||||
state = new_state;
|
||||
|
||||
MIDI::byte msg = 0;
|
||||
|
||||
switch (state.state()) {
|
||||
case LedState::on:
|
||||
msg = 0x7f;
|
||||
break;
|
||||
case LedState::off:
|
||||
msg = 0x00;
|
||||
break;
|
||||
case LedState::flashing:
|
||||
msg = 0x01;
|
||||
break;
|
||||
case LedState::none:
|
||||
return MidiByteArray ();
|
||||
}
|
||||
|
||||
return MidiByteArray (3, 0x90, id(), msg);
|
||||
}
|
||||
66
libs/surfaces/us2400/led.h
Normal file
66
libs/surfaces/us2400/led.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
|
||||
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_us2400_control_protocol_led_h__
|
||||
#define __ardour_us2400_control_protocol_led_h__
|
||||
|
||||
#include "controls.h"
|
||||
#include "midi_byte_array.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
class Led : public Control
|
||||
{
|
||||
public:
|
||||
static const int FaderTouch;
|
||||
static const int Timecode;
|
||||
static const int Beats;
|
||||
static const int RudeSolo;
|
||||
static const int RelayClick;
|
||||
|
||||
Led (int id, std::string name, Group & group)
|
||||
: Control (id, name, group)
|
||||
, state (off)
|
||||
, last_state (off)
|
||||
, llast_state (off)
|
||||
{
|
||||
}
|
||||
|
||||
Led & led() { return *this; }
|
||||
MidiByteArray set_state (LedState);
|
||||
|
||||
MidiByteArray zero() { return set_state (off); }
|
||||
|
||||
static Control* factory (Surface&, int id, const char*, Group&);
|
||||
|
||||
private:
|
||||
LedState state;
|
||||
LedState last_state;
|
||||
LedState llast_state;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ardour_us2400_control_protocol_led_h__ */
|
||||
1111
libs/surfaces/us2400/mcp_buttons.cc
Normal file
1111
libs/surfaces/us2400/mcp_buttons.cc
Normal file
File diff suppressed because it is too large
Load Diff
137
libs/surfaces/us2400/meter.cc
Normal file
137
libs/surfaces/us2400/meter.cc
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
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 <cmath>
|
||||
|
||||
#include "pbd/compose.h"
|
||||
#include "ardour/debug.h"
|
||||
|
||||
#include "meter.h"
|
||||
#include "surface.h"
|
||||
#include "surface_port.h"
|
||||
#include "control_group.h"
|
||||
#include "us2400_control_protocol.h"
|
||||
|
||||
using namespace PBD;
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
Control*
|
||||
Meter::factory (Surface& surface, int id, const char* name, Group& group)
|
||||
{
|
||||
Meter* m = new Meter (id, name, group);
|
||||
surface.meters[id] = m;
|
||||
surface.controls.push_back (m);
|
||||
group.add (*m);
|
||||
return m;
|
||||
}
|
||||
|
||||
void
|
||||
Meter::notify_metering_state_changed(Surface& surface, bool transport_is_rolling, bool metering_active)
|
||||
{
|
||||
return;
|
||||
|
||||
MidiByteArray msg;
|
||||
|
||||
// sysex header
|
||||
msg << surface.sysex_hdr();
|
||||
|
||||
// code for Channel Meter Enable Message
|
||||
msg << 0x20;
|
||||
|
||||
// Channel identification
|
||||
msg << id();
|
||||
|
||||
// Enable (0x07) / Disable (0x00) level meter on LCD, peak hold display on horizontal meter and signal LED
|
||||
_enabled = ((surface.mcp().device_info().has_separate_meters() || transport_is_rolling) && metering_active);
|
||||
msg << (_enabled ? 0x07 : 0x00);
|
||||
|
||||
// sysex trailer
|
||||
msg << MIDI::eox;
|
||||
|
||||
surface.write (msg);
|
||||
}
|
||||
|
||||
void
|
||||
Meter::send_update (Surface& surface, float dB)
|
||||
{
|
||||
|
||||
float def = 0.0f; /* Meter deflection %age */
|
||||
|
||||
// DEBUG_TRACE (DEBUG::US2400, string_compose ("Meter ID %1 dB %2\n", id(), dB));
|
||||
|
||||
if (dB < -70.0f) {
|
||||
def = 0.0f;
|
||||
} else if (dB < -60.0f) {
|
||||
def = (dB + 70.0f) * 0.25f;
|
||||
} else if (dB < -50.0f) {
|
||||
def = (dB + 60.0f) * 0.5f + 2.5f;
|
||||
} else if (dB < -40.0f) {
|
||||
def = (dB + 50.0f) * 0.75f + 7.5f;
|
||||
} else if (dB < -30.0f) {
|
||||
def = (dB + 40.0f) * 1.5f + 15.0f;
|
||||
} else if (dB < -20.0f) {
|
||||
def = (dB + 30.0f) * 2.0f + 30.0f;
|
||||
} else if (dB < 6.0f) {
|
||||
def = (dB + 20.0f) * 2.5f + 50.0f;
|
||||
} else {
|
||||
def = 115.0f;
|
||||
}
|
||||
|
||||
/* 115 is the deflection %age that would be
|
||||
when dB=6.0. this is an arbitrary
|
||||
endpoint for our scaling.
|
||||
*/
|
||||
|
||||
MidiByteArray msg;
|
||||
|
||||
if (def > 100.0f) {
|
||||
if (!overload_on) {
|
||||
overload_on = true;
|
||||
surface.write (MidiByteArray (2, 0xd0, (id() << 4) | 0xe));
|
||||
}
|
||||
} else {
|
||||
if (overload_on) {
|
||||
overload_on = false;
|
||||
surface.write (MidiByteArray (2, 0xd0, (id() << 4) | 0xf));
|
||||
}
|
||||
}
|
||||
|
||||
/* we can use up to 13 segments */
|
||||
|
||||
int segment = lrintf ((def/115.0) * 13.0);
|
||||
|
||||
//only send an update 'twice'
|
||||
if (segment == last_update_segment) {
|
||||
if (segment == llast_update_segment) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
llast_update_segment = last_update_segment;
|
||||
last_update_segment = segment;
|
||||
|
||||
|
||||
surface.write (MidiByteArray (2, 0xd0, (id()<<4) | segment));
|
||||
}
|
||||
|
||||
MidiByteArray
|
||||
Meter::zero ()
|
||||
{
|
||||
return MidiByteArray (2, 0xD0, (id()<<4 | 0));
|
||||
}
|
||||
66
libs/surfaces/us2400/meter.h
Normal file
66
libs/surfaces/us2400/meter.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
|
||||
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_us2400_control_protocol_meter_h__
|
||||
#define __ardour_us2400_control_protocol_meter_h__
|
||||
|
||||
#include "controls.h"
|
||||
#include "midi_byte_array.h"
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
class SurfacePort;
|
||||
|
||||
class Meter : public Control
|
||||
{
|
||||
public:
|
||||
Meter (int id, std::string name, Group & group)
|
||||
: Control (id, name, group)
|
||||
, _enabled (false)
|
||||
, overload_on (false),
|
||||
last_update_segment (-1),
|
||||
llast_update_segment (-1)
|
||||
{}
|
||||
|
||||
|
||||
void send_update (Surface&, float dB);
|
||||
bool enabled () const { return _enabled; }
|
||||
|
||||
MidiByteArray zero();
|
||||
|
||||
static Control* factory (Surface&, int id, const char*, Group&);
|
||||
|
||||
void notify_metering_state_changed(Surface& surface, bool transport_is_rolling, bool metering_active);
|
||||
|
||||
private:
|
||||
bool _enabled;
|
||||
bool overload_on;
|
||||
|
||||
int last_update_segment;
|
||||
int llast_update_segment;
|
||||
};
|
||||
|
||||
} // US2400 namespace
|
||||
} // ArdourSurface namespace
|
||||
|
||||
#endif /* __ardour_us2400_control_protocol_meter_h__ */
|
||||
96
libs/surfaces/us2400/midi_byte_array.cc
Normal file
96
libs/surfaces/us2400/midi_byte_array.cc
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
|
||||
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 "midi_byte_array.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace std;
|
||||
|
||||
MidiByteArray::MidiByteArray (size_t size, MIDI::byte array[])
|
||||
: std::vector<MIDI::byte>()
|
||||
{
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
push_back (array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
MidiByteArray::MidiByteArray (size_t count, MIDI::byte first, ...)
|
||||
: vector<MIDI::byte>()
|
||||
{
|
||||
push_back (first);
|
||||
va_list var_args;
|
||||
va_start (var_args, first);
|
||||
for (size_t i = 1; i < count; ++i)
|
||||
{
|
||||
MIDI::byte b = va_arg (var_args, int);
|
||||
push_back (b);
|
||||
}
|
||||
va_end (var_args);
|
||||
}
|
||||
|
||||
|
||||
void MidiByteArray::copy (size_t count, MIDI::byte * arr)
|
||||
{
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
push_back (arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
MidiByteArray & operator << (MidiByteArray & mba, const MIDI::byte & b)
|
||||
{
|
||||
mba.push_back (b);
|
||||
return mba;
|
||||
}
|
||||
|
||||
MidiByteArray & operator << (MidiByteArray & mba, const MidiByteArray & barr)
|
||||
{
|
||||
back_insert_iterator<MidiByteArray> bit (mba);
|
||||
copy (barr.begin(), barr.end(), bit);
|
||||
return mba;
|
||||
}
|
||||
|
||||
ostream & operator << (ostream & os, const MidiByteArray & mba)
|
||||
{
|
||||
os << "[";
|
||||
char fill = os.fill('0');
|
||||
for (MidiByteArray::const_iterator it = mba.begin(); it != mba.end(); ++it) {
|
||||
if (it != mba.begin()) os << " ";
|
||||
os << hex << setw(2) << (int)*it;
|
||||
}
|
||||
os.fill (fill);
|
||||
os << dec;
|
||||
os << "]";
|
||||
return os;
|
||||
}
|
||||
|
||||
MidiByteArray & operator << (MidiByteArray & mba, const std::string & st)
|
||||
{
|
||||
/* note that this assumes that "st" is ASCII encoded
|
||||
*/
|
||||
|
||||
mba.insert (mba.end(), st.begin(), st.end());
|
||||
return mba;
|
||||
}
|
||||
76
libs/surfaces/us2400/midi_byte_array.h
Normal file
76
libs/surfaces/us2400/midi_byte_array.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
|
||||
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 midi_byte_array_h
|
||||
#define midi_byte_array_h
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/shared_array.hpp>
|
||||
|
||||
//#include <midi++/types.h>
|
||||
namespace MIDI {
|
||||
typedef unsigned char byte;
|
||||
}
|
||||
|
||||
/**
|
||||
To make building arrays of bytes easier. Thusly:
|
||||
|
||||
MidiByteArray mba;
|
||||
mba << 0xf0 << 0x00 << 0xf7;
|
||||
|
||||
MidiByteArray buf;
|
||||
buf << mba;
|
||||
|
||||
MidiByteArray direct( 3, 0xf0, 0x00, 0xf7 );
|
||||
|
||||
cout << mba << endl;
|
||||
cout << buf << endl;
|
||||
cout << direct << endl;
|
||||
|
||||
will all result in "f0 00 f7" being output to stdout
|
||||
*/
|
||||
class MidiByteArray : public std::vector<MIDI::byte>
|
||||
{
|
||||
public:
|
||||
MidiByteArray() : std::vector<MIDI::byte>() {}
|
||||
|
||||
MidiByteArray( size_t count, MIDI::byte array[] );
|
||||
|
||||
/**
|
||||
Accepts a preceding count, and then a list of bytes
|
||||
*/
|
||||
MidiByteArray( size_t count, MIDI::byte first, ... );
|
||||
|
||||
/// copy the given number of bytes from the given array
|
||||
void copy( size_t count, MIDI::byte arr[] );
|
||||
};
|
||||
|
||||
/// append the given byte to the end of the array
|
||||
MidiByteArray & operator << ( MidiByteArray & mba, const MIDI::byte & b );
|
||||
|
||||
/// append the given string to the end of the array
|
||||
MidiByteArray & operator << ( MidiByteArray & mba, const std::string & );
|
||||
|
||||
/// append the given array to the end of this array
|
||||
MidiByteArray & operator << ( MidiByteArray & mba, const MidiByteArray & barr );
|
||||
|
||||
/// output the bytes as hex to the given stream
|
||||
std::ostream & operator << ( std::ostream & os, const MidiByteArray & mba );
|
||||
|
||||
#endif
|
||||
86
libs/surfaces/us2400/pot.cc
Normal file
86
libs/surfaces/us2400/pot.cc
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
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 <cmath>
|
||||
|
||||
#include "pot.h"
|
||||
#include "surface.h"
|
||||
#include "control_group.h"
|
||||
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
int const Pot::External = 0x2e; /* specific ID for "vpot" representing external control */
|
||||
int const Pot::ID = 0x10; /* base value for v-pot IDs */
|
||||
|
||||
Control*
|
||||
Pot::factory (Surface& surface, int id, const char* name, Group& group)
|
||||
{
|
||||
Pot* p = new Pot (id, name, group);
|
||||
surface.pots[id] = p;
|
||||
surface.controls.push_back (p);
|
||||
group.add (*p);
|
||||
return p;
|
||||
}
|
||||
|
||||
MidiByteArray
|
||||
Pot::set (float val, bool onoff)
|
||||
{
|
||||
int posi = lrintf (128.0 * val);
|
||||
if (posi == last_update_position) {
|
||||
if (posi == llast_update_position) {
|
||||
return MidiByteArray();
|
||||
}
|
||||
}
|
||||
llast_update_position = last_update_position;
|
||||
last_update_position = posi;
|
||||
|
||||
// TODO do an exact calc for 0.50? To allow manually re-centering the port.
|
||||
|
||||
// center on if val is "very close" to 0.50
|
||||
MIDI::byte msg = (val > 0.48 && val < 0.58 ? 1 : 0) << 6;
|
||||
|
||||
// Pot/LED mode
|
||||
msg |= (_mode << 4);
|
||||
|
||||
/*
|
||||
* Even though a width value may be negative, there is
|
||||
* technically still width there, it is just reversed,
|
||||
* so make sure to show it on the LED ring appropriately.
|
||||
*/
|
||||
if (val < 0){
|
||||
val = val * -1;
|
||||
}
|
||||
|
||||
// val, but only if off hasn't explicitly been set
|
||||
if (onoff) {
|
||||
if (_mode == spread) {
|
||||
msg |= (lrintf (val * 6)) & 0x0f; // 0b00001111
|
||||
} else {
|
||||
msg |= (lrintf (val * 10.0) + 1) & 0x0f; // 0b00001111
|
||||
}
|
||||
}
|
||||
|
||||
/* outbound LED message requires 0x20 to be added to the LED's id
|
||||
*/
|
||||
|
||||
return MidiByteArray (3, 0xb0, 0x20 + id(), msg);
|
||||
|
||||
}
|
||||
|
||||
64
libs/surfaces/us2400/pot.h
Normal file
64
libs/surfaces/us2400/pot.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_us2400_control_protocol_pot_h__
|
||||
#define __ardour_us2400_control_protocol_pot_h__
|
||||
|
||||
#include "controls.h"
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
class Pot : public Control
|
||||
{
|
||||
public:
|
||||
static int const External;
|
||||
static int const ID;
|
||||
|
||||
enum Mode {
|
||||
dot = 0,
|
||||
boost_cut = 1,
|
||||
wrap = 2,
|
||||
spread = 3
|
||||
};
|
||||
|
||||
Pot (int id, std::string name, Group & group)
|
||||
: Control (id, name, group),
|
||||
last_update_position (-1),
|
||||
llast_update_position (-1) {}
|
||||
|
||||
void set_mode(Mode m) {_mode = m; last_update_position = -1; }
|
||||
|
||||
MidiByteArray set (float, bool);
|
||||
MidiByteArray zero() { return set (0.0, false); }
|
||||
|
||||
static Control* factory (Surface&, int id, const char*, Group&);
|
||||
|
||||
int last_update_position;
|
||||
int llast_update_position;
|
||||
|
||||
Mode _mode;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ardour_us2400_control_protocol_pot_h__ */
|
||||
970
libs/surfaces/us2400/strip.cc
Normal file
970
libs/surfaces/us2400/strip.cc
Normal file
@@ -0,0 +1,970 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
Copyright (C) 2012 Paul Davis
|
||||
Copyright (C) 2017 Ben Loftis
|
||||
|
||||
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 <sstream>
|
||||
#include <vector>
|
||||
#include <climits>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
#include <glibmm/convert.h>
|
||||
|
||||
#include "midi++/port.h"
|
||||
|
||||
#include "pbd/compose.h"
|
||||
#include "pbd/convert.h"
|
||||
|
||||
#include "ardour/amp.h"
|
||||
#include "ardour/bundle.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/midi_ui.h"
|
||||
#include "ardour/meter.h"
|
||||
#include "ardour/monitor_control.h"
|
||||
#include "ardour/plugin_insert.h"
|
||||
#include "ardour/pannable.h"
|
||||
#include "ardour/panner.h"
|
||||
#include "ardour/panner_shell.h"
|
||||
#include "ardour/phase_control.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
#include "ardour/record_enable_control.h"
|
||||
#include "ardour/route.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/send.h"
|
||||
#include "ardour/solo_isolate_control.h"
|
||||
#include "ardour/track.h"
|
||||
#include "ardour/midi_track.h"
|
||||
#include "ardour/user_bundle.h"
|
||||
#include "ardour/profile.h"
|
||||
#include "ardour/value_as_string.h"
|
||||
|
||||
#include "us2400_control_protocol.h"
|
||||
#include "surface_port.h"
|
||||
#include "surface.h"
|
||||
#include "strip.h"
|
||||
#include "button.h"
|
||||
#include "led.h"
|
||||
#include "pot.h"
|
||||
#include "fader.h"
|
||||
#include "jog.h"
|
||||
#include "meter.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace ARDOUR;
|
||||
using namespace PBD;
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
#ifndef timeradd /// only avail with __USE_BSD
|
||||
#define timeradd(a,b,result) \
|
||||
do { \
|
||||
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
|
||||
(result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
|
||||
if ((result)->tv_usec >= 1000000) \
|
||||
{ \
|
||||
++(result)->tv_sec; \
|
||||
(result)->tv_usec -= 1000000; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define ui_context() US2400Protocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
|
||||
|
||||
Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::ID,StripButtonInfo>& strip_buttons)
|
||||
: Group (name)
|
||||
, _solo (0)
|
||||
, _mute (0)
|
||||
, _select (0)
|
||||
, _fader_touch (0)
|
||||
, _vpot (0)
|
||||
, _fader (0)
|
||||
, _meter (0)
|
||||
, _index (index)
|
||||
, _surface (&s)
|
||||
, _controls_locked (false)
|
||||
, _transport_is_rolling (false)
|
||||
, _metering_active (true)
|
||||
, _pan_mode (PanAzimuthAutomation)
|
||||
{
|
||||
_fader = dynamic_cast<Fader*> (Fader::factory (*_surface, index, "fader", *this));
|
||||
_vpot = dynamic_cast<Pot*> (Pot::factory (*_surface, Pot::ID + index, "vpot", *this));
|
||||
|
||||
if (s.mcp().device_info().has_meters()) {
|
||||
_meter = dynamic_cast<Meter*> (Meter::factory (*_surface, index, "meter", *this));
|
||||
}
|
||||
|
||||
for (map<Button::ID,StripButtonInfo>::const_iterator b = strip_buttons.begin(); b != strip_buttons.end(); ++b) {
|
||||
Button* bb = dynamic_cast<Button*> (Button::factory (*_surface, b->first, b->second.base_id + index, b->second.name, *this));
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("surface %1 strip %2 new button BID %3 id %4 from base %5\n",
|
||||
_surface->number(), index, Button::id_to_name (bb->bid()),
|
||||
bb->id(), b->second.base_id));
|
||||
}
|
||||
|
||||
_trickle_counter = 0;
|
||||
}
|
||||
|
||||
Strip::~Strip ()
|
||||
{
|
||||
/* surface is responsible for deleting all controls */
|
||||
}
|
||||
|
||||
void
|
||||
Strip::add (Control & control)
|
||||
{
|
||||
Button* button;
|
||||
|
||||
Group::add (control);
|
||||
|
||||
/* fader, vpot, meter were all set explicitly */
|
||||
|
||||
if ((button = dynamic_cast<Button*>(&control)) != 0) {
|
||||
switch (button->bid()) {
|
||||
case Button::Mute:
|
||||
_mute = button;
|
||||
break;
|
||||
case Button::Solo:
|
||||
_solo = button;
|
||||
break;
|
||||
case Button::Select:
|
||||
_select = button;
|
||||
break;
|
||||
case Button::FaderTouch:
|
||||
_fader_touch = button;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Strip::set_stripable (boost::shared_ptr<Stripable> r, bool /*with_messages*/)
|
||||
{
|
||||
if (_controls_locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
stripable_connections.drop_connections ();
|
||||
|
||||
_solo->set_control (boost::shared_ptr<AutomationControl>());
|
||||
_mute->set_control (boost::shared_ptr<AutomationControl>());
|
||||
_select->set_control (boost::shared_ptr<AutomationControl>());
|
||||
|
||||
_fader->set_control (boost::shared_ptr<AutomationControl>());
|
||||
_vpot->set_control (boost::shared_ptr<AutomationControl>());
|
||||
|
||||
_stripable = r;
|
||||
|
||||
reset_saved_values ();
|
||||
|
||||
if (!r) {
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface %1 Strip %2 mapped to null route\n", _surface->number(), _index));
|
||||
zero ();
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("Surface %1 strip %2 now mapping stripable %3\n",
|
||||
_surface->number(), _index, _stripable->name()));
|
||||
|
||||
_solo->set_control (_stripable->solo_control());
|
||||
_mute->set_control (_stripable->mute_control());
|
||||
|
||||
_stripable->solo_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_solo_changed, this), ui_context());
|
||||
_stripable->mute_control()->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_mute_changed, this), ui_context());
|
||||
|
||||
boost::shared_ptr<AutomationControl> pan_control = _stripable->pan_azimuth_control();
|
||||
if (pan_control) {
|
||||
pan_control->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_azi_changed, this, false), ui_context());
|
||||
}
|
||||
|
||||
pan_control = _stripable->pan_width_control();
|
||||
if (pan_control) {
|
||||
pan_control->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_panner_width_changed, this, false), ui_context());
|
||||
}
|
||||
|
||||
_stripable->gain_control()->Changed.connect(stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_gain_changed, this, false), ui_context());
|
||||
_stripable->PropertyChanged.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
|
||||
_stripable->presentation_info().PropertyChanged.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_property_changed, this, _1), ui_context());
|
||||
|
||||
// TODO this works when a currently-banked stripable is made inactive, but not
|
||||
// when a stripable is activated which should be currently banked.
|
||||
|
||||
_stripable->DropReferences.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_stripable_deleted, this), ui_context());
|
||||
|
||||
/* setup legal VPot modes for this stripable */
|
||||
|
||||
possible_pot_parameters.clear();
|
||||
|
||||
if (_stripable->pan_azimuth_control()) {
|
||||
possible_pot_parameters.push_back (PanAzimuthAutomation);
|
||||
}
|
||||
if (_stripable->pan_width_control()) {
|
||||
possible_pot_parameters.push_back (PanWidthAutomation);
|
||||
}
|
||||
if (_stripable->pan_elevation_control()) {
|
||||
possible_pot_parameters.push_back (PanElevationAutomation);
|
||||
}
|
||||
if (_stripable->pan_frontback_control()) {
|
||||
possible_pot_parameters.push_back (PanFrontBackAutomation);
|
||||
}
|
||||
if (_stripable->pan_lfe_control()) {
|
||||
possible_pot_parameters.push_back (PanLFEAutomation);
|
||||
}
|
||||
|
||||
_pan_mode = PanAzimuthAutomation;
|
||||
|
||||
if (_surface->mcp().subview_mode() == US2400Protocol::None) {
|
||||
set_vpot_parameter (_pan_mode);
|
||||
}
|
||||
|
||||
_fader->set_control (_stripable->gain_control());
|
||||
|
||||
notify_all ();
|
||||
}
|
||||
|
||||
void
|
||||
Strip::reset_stripable ()
|
||||
{
|
||||
stripable_connections.drop_connections ();
|
||||
|
||||
_solo->set_control (boost::shared_ptr<AutomationControl>());
|
||||
_mute->set_control (boost::shared_ptr<AutomationControl>());
|
||||
_select->set_control (boost::shared_ptr<AutomationControl>());
|
||||
|
||||
_fader->reset_control ();
|
||||
_vpot->reset_control ();
|
||||
|
||||
_stripable.reset();
|
||||
|
||||
reset_saved_values ();
|
||||
|
||||
notify_all ();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Strip::notify_all()
|
||||
{
|
||||
// if (!_stripable) {
|
||||
// zero ();
|
||||
// return;
|
||||
// }
|
||||
// The active V-pot control may not be active for this strip
|
||||
// But if we zero it in the controls function it may erase
|
||||
// the one we do want
|
||||
// _surface->write (_vpot->zero());
|
||||
|
||||
notify_solo_changed ();
|
||||
notify_mute_changed ();
|
||||
notify_gain_changed ();
|
||||
notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
|
||||
notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::selected));
|
||||
notify_panner_azi_changed ();
|
||||
notify_vpot_change ();
|
||||
notify_panner_width_changed ();
|
||||
notify_record_enable_changed ();
|
||||
// notify_processor_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_solo_changed ()
|
||||
{
|
||||
// if (_stripable && _solo) {
|
||||
// _surface->write (_solo->set_state (_stripable->solo_control()->soloed() ? on : off));
|
||||
// }
|
||||
|
||||
_trickle_counter = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_mute_changed ()
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("Strip %1 mute changed\n", _index));
|
||||
// if (_stripable && _mute) {
|
||||
// DEBUG_TRACE (DEBUG::US2400, string_compose ("\tstripable muted ? %1\n", _stripable->mute_control()->muted()));
|
||||
// DEBUG_TRACE (DEBUG::US2400, string_compose ("mute message: %1\n", _mute->set_state (_stripable->mute_control()->muted() ? on : off)));
|
||||
//
|
||||
// _surface->write (_mute->set_state (_stripable->mute_control()->muted() ? on : off));
|
||||
// } else {
|
||||
// _surface->write (_mute->zero());
|
||||
// }
|
||||
|
||||
_trickle_counter = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_record_enable_changed ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_stripable_deleted ()
|
||||
{
|
||||
_surface->mcp().notify_stripable_removed ();
|
||||
_surface->mcp().refresh_current_bank();
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_gain_changed (bool force_update)
|
||||
{
|
||||
_trickle_counter = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_processor_changed (bool force_update)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_property_changed (const PropertyChange& what_changed)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::update_selection_state ()
|
||||
{
|
||||
_trickle_counter = 0;
|
||||
|
||||
// if(_stripable) {
|
||||
// _surface->write (_select->set_state (_stripable->is_selected()));
|
||||
// }
|
||||
}
|
||||
|
||||
void
|
||||
Strip::show_stripable_name ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_vpot_change ()
|
||||
{
|
||||
_trickle_counter = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_panner_azi_changed (bool force_update)
|
||||
{
|
||||
_trickle_counter = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_panner_width_changed (bool force_update)
|
||||
{
|
||||
_trickle_counter = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::select_event (Button&, ButtonState bs)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::US2400, "select button\n");
|
||||
|
||||
if (bs == press) {
|
||||
|
||||
int ms = _surface->mcp().main_modifier_state();
|
||||
|
||||
if (ms & US2400Protocol::MODIFIER_CMDALT) {
|
||||
_controls_locked = !_controls_locked;
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::US2400, "add select button on press\n");
|
||||
_surface->mcp().add_down_select_button (_surface->number(), _index);
|
||||
_surface->mcp().select_range (_surface->mcp().global_index (*this));
|
||||
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::US2400, "remove select button on release\n");
|
||||
_surface->mcp().remove_down_select_button (_surface->number(), _index);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Strip::vselect_event (Button&, ButtonState bs)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::fader_touch_event (Button&, ButtonState bs)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("fader touch, press ? %1\n", (bs == press)));
|
||||
|
||||
if (bs == press) {
|
||||
|
||||
boost::shared_ptr<AutomationControl> ac = _fader->control ();
|
||||
|
||||
_fader->set_in_use (true);
|
||||
_fader->start_touch (_surface->mcp().transport_frame());
|
||||
|
||||
} else {
|
||||
|
||||
_fader->set_in_use (false);
|
||||
_fader->stop_touch (_surface->mcp().transport_frame());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Strip::handle_button (Button& button, ButtonState bs)
|
||||
{
|
||||
boost::shared_ptr<AutomationControl> control;
|
||||
|
||||
if (bs == press) {
|
||||
button.set_in_use (true);
|
||||
} else {
|
||||
button.set_in_use (false);
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("strip %1 handling button %2 press ? %3\n", _index, button.bid(), (bs == press)));
|
||||
|
||||
switch (button.bid()) {
|
||||
case Button::Select:
|
||||
select_event (button, bs);
|
||||
break;
|
||||
|
||||
case Button::FaderTouch:
|
||||
fader_touch_event (button, bs);
|
||||
break;
|
||||
|
||||
default:
|
||||
if ((control = button.control ())) {
|
||||
if (bs == press) {
|
||||
DEBUG_TRACE (DEBUG::US2400, "add button on press\n");
|
||||
_surface->mcp().add_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
|
||||
|
||||
float new_value = control->get_value() ? 0.0 : 1.0;
|
||||
|
||||
/* get all controls that either have their
|
||||
* button down or are within a range of
|
||||
* several down buttons
|
||||
*/
|
||||
|
||||
US2400Protocol::ControlList controls = _surface->mcp().down_controls ((AutomationType) control->parameter().type(),
|
||||
_surface->mcp().global_index(*this));
|
||||
|
||||
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("there are %1 buttons down for control type %2, new value = %3\n",
|
||||
controls.size(), control->parameter().type(), new_value));
|
||||
|
||||
/* apply change, with potential modifier semantics */
|
||||
|
||||
Controllable::GroupControlDisposition gcd;
|
||||
|
||||
if (_surface->mcp().main_modifier_state() & US2400Protocol::MODIFIER_SHIFT) {
|
||||
gcd = Controllable::InverseGroup;
|
||||
} else {
|
||||
gcd = Controllable::UseGroup;
|
||||
}
|
||||
|
||||
for (US2400Protocol::ControlList::iterator c = controls.begin(); c != controls.end(); ++c) {
|
||||
(*c)->set_value (new_value, gcd);
|
||||
}
|
||||
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::US2400, "remove button on release\n");
|
||||
_surface->mcp().remove_down_button ((AutomationType) control->parameter().type(), _surface->number(), _index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Strip::handle_fader_touch (Fader& fader, bool touch_on)
|
||||
{
|
||||
if (touch_on) {
|
||||
fader.start_touch (_surface->mcp().transport_frame());
|
||||
} else {
|
||||
fader.stop_touch (_surface->mcp().transport_frame());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Strip::handle_fader (Fader& fader, float position)
|
||||
{
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("fader to %1\n", position));
|
||||
boost::shared_ptr<AutomationControl> ac = fader.control();
|
||||
if (!ac) {
|
||||
return;
|
||||
}
|
||||
|
||||
Controllable::GroupControlDisposition gcd = Controllable::UseGroup;
|
||||
|
||||
if (_surface->mcp().main_modifier_state() & US2400Protocol::MODIFIER_SHIFT) {
|
||||
gcd = Controllable::InverseGroup;
|
||||
}
|
||||
|
||||
fader.set_value (position, gcd);
|
||||
|
||||
/* From the Mackie Control MIDI implementation docs:
|
||||
|
||||
In order to ensure absolute synchronization with the host software,
|
||||
Mackie Control uses a closed-loop servo system for the faders,
|
||||
meaning the faders will always move to their last received position.
|
||||
When a host receives a Fader Position Message, it must then
|
||||
re-transmit that message to the Mackie Control or else the faders
|
||||
will return to their last position.
|
||||
*/
|
||||
|
||||
_surface->write (fader.set_position (position));
|
||||
}
|
||||
|
||||
void
|
||||
Strip::handle_pot (Pot& pot, float delta)
|
||||
{
|
||||
/* Pots only emit events when they move, not when they
|
||||
stop moving. So to get a stop event, we need to use a timeout.
|
||||
*/
|
||||
|
||||
boost::shared_ptr<AutomationControl> ac = pot.control();
|
||||
if (!ac) {
|
||||
return;
|
||||
}
|
||||
|
||||
Controllable::GroupControlDisposition gcd;
|
||||
|
||||
if (_surface->mcp().main_modifier_state() & US2400Protocol::MODIFIER_SHIFT) {
|
||||
gcd = Controllable::InverseGroup;
|
||||
} else {
|
||||
gcd = Controllable::UseGroup;
|
||||
}
|
||||
|
||||
if (ac->toggled()) {
|
||||
|
||||
/* make it like a single-step, directional switch */
|
||||
|
||||
if (delta > 0) {
|
||||
ac->set_value (1.0, gcd);
|
||||
} else {
|
||||
ac->set_value (0.0, gcd);
|
||||
}
|
||||
|
||||
} else if (ac->desc().enumeration || ac->desc().integer_step) {
|
||||
|
||||
/* use Controllable::get_value() to avoid the
|
||||
* "scaling-to-interface" that takes place in
|
||||
* Control::get_value() via the pot member.
|
||||
*
|
||||
* an enumeration with 4 values will have interface values of
|
||||
* 0.0, 0.25, 0.5 and 0.75 or some similar oddness. Lets not
|
||||
* deal with that.
|
||||
*/
|
||||
|
||||
if (delta > 0) {
|
||||
ac->set_value (min (ac->upper(), ac->get_value() + 1.0), gcd);
|
||||
} else {
|
||||
ac->set_value (max (ac->lower(), ac->get_value() - 1.0), gcd);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
double p = ac->get_interface();
|
||||
|
||||
p += delta;
|
||||
|
||||
p = max (0.0, p);
|
||||
p = min (1.0, p);
|
||||
|
||||
ac->set_value ( ac->interface_to_internal(p), gcd);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Strip::periodic (ARDOUR::microseconds_t now)
|
||||
{
|
||||
|
||||
update_meter ();
|
||||
|
||||
if ( _trickle_counter %5 == 0 ) {
|
||||
|
||||
if ( _fader->control() ) {
|
||||
_surface->write (_fader->set_position (_fader->control()->internal_to_interface (_fader->control()->get_value ())));
|
||||
} else {
|
||||
_surface->write (_fader->set_position(0.0));
|
||||
}
|
||||
|
||||
if ( _vpot->control() ) {
|
||||
_surface->write (_vpot->set (_vpot->control()->internal_to_interface (_vpot->control()->get_value ()), true));
|
||||
} else {
|
||||
_surface->write (_vpot->set(0.0, false));
|
||||
}
|
||||
|
||||
if (_stripable) {
|
||||
_surface->write (_solo->set_state (_stripable->solo_control()->soloed() ? on : off));
|
||||
_surface->write (_mute->set_state (_stripable->mute_control()->muted() ? on : off));
|
||||
_surface->write (_select->set_state (_stripable->is_selected()));
|
||||
} else {
|
||||
_surface->write (_solo->set_state (off));
|
||||
_surface->write (_mute->set_state (off));
|
||||
_surface->write (_select->set_state (off));
|
||||
}
|
||||
|
||||
}
|
||||
_trickle_counter++;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::redisplay (ARDOUR::microseconds_t now, bool force)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::update_automation ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::update_meter ()
|
||||
{
|
||||
if (!_stripable) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_meter && _transport_is_rolling && _metering_active && _stripable->peak_meter()) {
|
||||
float dB = _stripable->peak_meter()->meter_level (0, MeterMCP);
|
||||
_meter->send_update (*_surface, dB);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Strip::zero ()
|
||||
{
|
||||
_trickle_counter = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::lock_controls ()
|
||||
{
|
||||
_controls_locked = true;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::unlock_controls ()
|
||||
{
|
||||
_controls_locked = false;
|
||||
}
|
||||
|
||||
string
|
||||
Strip::vpot_mode_string ()
|
||||
{
|
||||
return "???";
|
||||
}
|
||||
|
||||
void
|
||||
Strip::next_pot_mode ()
|
||||
{
|
||||
vector<AutomationType>::iterator i;
|
||||
|
||||
boost::shared_ptr<AutomationControl> ac = _vpot->control();
|
||||
|
||||
if (!ac) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (_surface->mcp().subview_mode() != US2400Protocol::None) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (possible_pot_parameters.empty() || (possible_pot_parameters.size() == 1 && possible_pot_parameters.front() == ac->parameter().type())) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = possible_pot_parameters.begin(); i != possible_pot_parameters.end(); ++i) {
|
||||
if ((*i) == ac->parameter().type()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* move to the next mode in the list, or back to the start (which will
|
||||
also happen if the current mode is not in the current pot mode list)
|
||||
*/
|
||||
|
||||
if (i != possible_pot_parameters.end()) {
|
||||
++i;
|
||||
}
|
||||
|
||||
if (i == possible_pot_parameters.end()) {
|
||||
i = possible_pot_parameters.begin();
|
||||
}
|
||||
|
||||
set_vpot_parameter (*i);
|
||||
}
|
||||
|
||||
void
|
||||
/*
|
||||
*
|
||||
* name: Strip::subview_mode_changed
|
||||
* @param
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
Strip::subview_mode_changed ()
|
||||
{
|
||||
switch (_surface->mcp().subview_mode()) {
|
||||
|
||||
case US2400Protocol::None:
|
||||
set_vpot_parameter (_pan_mode);
|
||||
notify_metering_state_changed ();
|
||||
break;
|
||||
|
||||
case US2400Protocol::TrackView:
|
||||
boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
|
||||
if (r) {
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose("subview_mode_changed strip %1:%2- assigning trackview pot\n", _surface->number(), _index));
|
||||
setup_trackview_vpot (r);
|
||||
} else {
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose("subview_mode_changed strip %1:%2 - no stripable\n", _surface->number(), _index));
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
_trickle_counter = 0;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::setup_dyn_vpot (boost::shared_ptr<Stripable> r)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::setup_eq_vpot (boost::shared_ptr<Stripable> r)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
|
||||
{
|
||||
subview_connections.drop_connections ();
|
||||
|
||||
if (!r) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t global_pos = _surface->mcp().global_index (*this);
|
||||
|
||||
boost::shared_ptr<AutomationControl> pc;
|
||||
boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
|
||||
string label;
|
||||
|
||||
_vpot->set_mode(Pot::wrap);
|
||||
|
||||
#ifdef MIXBUS
|
||||
int eq_band = -1;
|
||||
if (r->is_input_strip ()) {
|
||||
|
||||
#ifdef MIXBUS32C
|
||||
switch (global_pos) {
|
||||
case 6:
|
||||
pc = r->filter_freq_controllable(true);
|
||||
break;
|
||||
case 7:
|
||||
pc = r->filter_freq_controllable(false);
|
||||
break;
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
case 14: {
|
||||
eq_band = (global_pos-8) / 2;
|
||||
pc = r->eq_freq_controllable (eq_band);
|
||||
} break;
|
||||
case 9:
|
||||
case 11:
|
||||
case 13:
|
||||
case 15: {
|
||||
eq_band = (global_pos-8) / 2;
|
||||
pc = r->eq_gain_controllable (eq_band);
|
||||
_vpot->set_mode(Pot::boost_cut);
|
||||
} break;
|
||||
}
|
||||
|
||||
#else //regular Mixbus channel EQ
|
||||
|
||||
switch (global_pos) {
|
||||
case 7:
|
||||
pc = r->filter_freq_controllable(true);
|
||||
break;
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
eq_band = (global_pos-8) / 2;
|
||||
pc = r->eq_gain_controllable (eq_band);
|
||||
_vpot->set_mode(Pot::boost_cut);
|
||||
break;
|
||||
case 9:
|
||||
case 11:
|
||||
case 13:
|
||||
eq_band = (global_pos-8) / 2;
|
||||
pc = r->eq_freq_controllable (eq_band);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
//trim & dynamics
|
||||
|
||||
switch (global_pos) {
|
||||
case 0:
|
||||
pc = r->trim_control ();
|
||||
_vpot->set_mode(Pot::boost_cut);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pc = r->pan_azimuth_control ();
|
||||
_vpot->set_mode(Pot::dot);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
pc = r->comp_threshold_controllable();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
pc = r->comp_speed_controllable();
|
||||
break;
|
||||
|
||||
case 4:
|
||||
pc = r->comp_mode_controllable();
|
||||
_vpot->set_mode(Pot::wrap);
|
||||
break;
|
||||
|
||||
case 5:
|
||||
pc = r->comp_makeup_controllable();
|
||||
break;
|
||||
|
||||
|
||||
} //trim & dynamics
|
||||
|
||||
//mixbus sends
|
||||
switch (global_pos) {
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
pc = r->send_level_controllable ( global_pos - 16 );
|
||||
break;
|
||||
|
||||
} //global_pos switch
|
||||
|
||||
} //if input_strip
|
||||
#endif //ifdef MIXBUS
|
||||
|
||||
if (pc) { //control found; set our knob to watch for changes in it
|
||||
_vpot->set_control (pc);
|
||||
pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_vpot_change, this), ui_context());
|
||||
} else { //no control, just set the knob to "empty"
|
||||
_vpot->reset_control ();
|
||||
}
|
||||
|
||||
notify_vpot_change ();
|
||||
}
|
||||
|
||||
void
|
||||
Strip::set_vpot_parameter (AutomationType p)
|
||||
{
|
||||
if (!_stripable || (p == NullAutomation)) {
|
||||
_vpot->set_control (boost::shared_ptr<AutomationControl>());
|
||||
return;
|
||||
}
|
||||
|
||||
boost::shared_ptr<AutomationControl> pan_control;
|
||||
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("switch to vpot mode %1\n", p));
|
||||
|
||||
reset_saved_values ();
|
||||
|
||||
switch (p) {
|
||||
case PanAzimuthAutomation:
|
||||
pan_control = _stripable->pan_azimuth_control ();
|
||||
break;
|
||||
case PanWidthAutomation:
|
||||
pan_control = _stripable->pan_width_control ();
|
||||
break;
|
||||
case PanElevationAutomation:
|
||||
break;
|
||||
case PanFrontBackAutomation:
|
||||
break;
|
||||
case PanLFEAutomation:
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (pan_control) {
|
||||
_pan_mode = p;
|
||||
_vpot->set_mode (Pot::dot);
|
||||
_vpot->set_control (pan_control);
|
||||
}
|
||||
|
||||
notify_panner_azi_changed (true);
|
||||
}
|
||||
|
||||
bool
|
||||
Strip::is_midi_track () const
|
||||
{
|
||||
return boost::dynamic_pointer_cast<MidiTrack>(_stripable) != 0;
|
||||
}
|
||||
|
||||
void
|
||||
Strip::reset_saved_values ()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
Strip::notify_metering_state_changed()
|
||||
{
|
||||
if (_surface->mcp().subview_mode() != US2400Protocol::None) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_stripable || !_meter) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool transport_is_rolling = (_surface->mcp().get_transport_speed () != 0.0f);
|
||||
bool metering_active = _surface->mcp().metering_active ();
|
||||
|
||||
if ((_transport_is_rolling == transport_is_rolling) && (_metering_active == metering_active)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_meter->notify_metering_state_changed (*_surface, transport_is_rolling, metering_active);
|
||||
|
||||
if (!transport_is_rolling || !metering_active) {
|
||||
notify_property_changed (PBD::PropertyChange (ARDOUR::Properties::name));
|
||||
notify_panner_azi_changed (true);
|
||||
}
|
||||
|
||||
_transport_is_rolling = transport_is_rolling;
|
||||
_metering_active = metering_active;
|
||||
}
|
||||
158
libs/surfaces/us2400/strip.h
Normal file
158
libs/surfaces/us2400/strip.h
Normal file
@@ -0,0 +1,158 @@
|
||||
#ifndef __ardour_us2400_control_protocol_strip_h__
|
||||
#define __ardour_us2400_control_protocol_strip_h__
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "evoral/Parameter.hpp"
|
||||
|
||||
#include "pbd/property_basics.h"
|
||||
#include "pbd/ringbuffer.h"
|
||||
#include "pbd/signals.h"
|
||||
|
||||
#include "ardour/types.h"
|
||||
#include "control_protocol/types.h"
|
||||
|
||||
#include "control_group.h"
|
||||
#include "types.h"
|
||||
#include "us2400_control_protocol.h"
|
||||
#include "midi_byte_array.h"
|
||||
#include "device_info.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class Stripable;
|
||||
class Bundle;
|
||||
class ChannelCount;
|
||||
}
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
class Control;
|
||||
class Surface;
|
||||
class Button;
|
||||
class Pot;
|
||||
class Fader;
|
||||
class Meter;
|
||||
class SurfacePort;
|
||||
|
||||
struct GlobalControlDefinition {
|
||||
const char* name;
|
||||
int id;
|
||||
Control* (*factory)(Surface&, int index, const char* name, Group&);
|
||||
const char* group_name;
|
||||
};
|
||||
|
||||
/**
|
||||
This is the set of controls that make up a strip.
|
||||
*/
|
||||
class Strip : public Group
|
||||
{
|
||||
public:
|
||||
Strip (Surface&, const std::string & name, int index, const std::map<Button::ID,StripButtonInfo>&);
|
||||
~Strip();
|
||||
|
||||
boost::shared_ptr<ARDOUR::Stripable> stripable() const { return _stripable; }
|
||||
|
||||
void add (Control & control);
|
||||
int index() const { return _index; } // zero based
|
||||
Surface* surface() const { return _surface; }
|
||||
|
||||
void set_stripable (boost::shared_ptr<ARDOUR::Stripable>, bool with_messages = true);
|
||||
void reset_stripable ();
|
||||
|
||||
// call all signal handlers manually
|
||||
void notify_all ();
|
||||
|
||||
void handle_button (Button&, ButtonState bs);
|
||||
void handle_fader (Fader&, float position);
|
||||
void handle_fader_touch (Fader&, bool touch_on);
|
||||
void handle_pot (Pot&, float delta);
|
||||
|
||||
void periodic (ARDOUR::microseconds_t now_usecs);
|
||||
void redisplay (ARDOUR::microseconds_t now_usecs, bool force = true);
|
||||
|
||||
void zero ();
|
||||
|
||||
void subview_mode_changed ();
|
||||
|
||||
void lock_controls ();
|
||||
void unlock_controls ();
|
||||
bool locked() const { return _controls_locked; }
|
||||
|
||||
void notify_metering_state_changed();
|
||||
|
||||
void update_selection_state ();
|
||||
|
||||
int global_index() { return _surface->mcp().global_index (*this); }
|
||||
|
||||
private:
|
||||
enum VPotDisplayMode {
|
||||
Name,
|
||||
Value
|
||||
};
|
||||
|
||||
Button* _solo;
|
||||
Button* _mute;
|
||||
Button* _select;
|
||||
Button* _fader_touch;
|
||||
Pot* _vpot;
|
||||
Fader* _fader;
|
||||
Meter* _meter;
|
||||
int _index;
|
||||
Surface* _surface;
|
||||
bool _controls_locked;
|
||||
bool _transport_is_rolling;
|
||||
bool _metering_active;
|
||||
boost::shared_ptr<ARDOUR::Stripable> _stripable;
|
||||
PBD::ScopedConnectionList stripable_connections;
|
||||
PBD::ScopedConnectionList subview_connections;
|
||||
PBD::ScopedConnectionList send_connections;
|
||||
int eq_band;
|
||||
|
||||
int _trickle_counter;
|
||||
|
||||
ARDOUR::AutomationType _pan_mode;
|
||||
|
||||
void notify_solo_changed ();
|
||||
void notify_mute_changed ();
|
||||
void notify_record_enable_changed ();
|
||||
void notify_gain_changed (bool force_update = true);
|
||||
void notify_property_changed (const PBD::PropertyChange&);
|
||||
void notify_panner_azi_changed (bool force_update = true);
|
||||
void notify_panner_width_changed (bool force_update = true);
|
||||
void notify_stripable_deleted ();
|
||||
void notify_processor_changed (bool force_update = true);
|
||||
void update_automation ();
|
||||
void update_meter ();
|
||||
std::string vpot_mode_string ();
|
||||
|
||||
void next_pot_mode ();
|
||||
|
||||
void select_event (Button&, ButtonState);
|
||||
void vselect_event (Button&, ButtonState);
|
||||
void fader_touch_event (Button&, ButtonState);
|
||||
|
||||
std::vector<ARDOUR::AutomationType> possible_pot_parameters;
|
||||
std::vector<ARDOUR::AutomationType> possible_trim_parameters;
|
||||
void set_vpot_parameter (ARDOUR::AutomationType);
|
||||
void show_stripable_name ();
|
||||
|
||||
void reset_saved_values ();
|
||||
|
||||
bool is_midi_track () const;
|
||||
|
||||
void notify_vpot_change ();
|
||||
|
||||
void setup_eq_vpot (boost::shared_ptr<ARDOUR::Stripable>);//
|
||||
void setup_dyn_vpot (boost::shared_ptr<ARDOUR::Stripable>);//
|
||||
void setup_sends_vpot (boost::shared_ptr<ARDOUR::Stripable>);//
|
||||
|
||||
void setup_trackview_vpot (boost::shared_ptr<ARDOUR::Stripable>);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __ardour_us2400_control_protocol_strip_h__ */
|
||||
1090
libs/surfaces/us2400/surface.cc
Normal file
1090
libs/surfaces/us2400/surface.cc
Normal file
File diff suppressed because it is too large
Load Diff
204
libs/surfaces/us2400/surface.h
Normal file
204
libs/surfaces/us2400/surface.h
Normal file
@@ -0,0 +1,204 @@
|
||||
#ifndef mackie_surface_h
|
||||
#define mackie_surface_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sigc++/trackable.h>
|
||||
|
||||
#include "pbd/signals.h"
|
||||
#include "pbd/xml++.h"
|
||||
#include "midi++/types.h"
|
||||
|
||||
#include "ardour/types.h"
|
||||
|
||||
#include "control_protocol/types.h"
|
||||
|
||||
#include "controls.h"
|
||||
#include "types.h"
|
||||
#include "jog_wheel.h"
|
||||
|
||||
namespace MIDI {
|
||||
class Parser;
|
||||
}
|
||||
|
||||
namespace ARDOUR {
|
||||
class Stripable;
|
||||
class Port;
|
||||
}
|
||||
|
||||
class MidiByteArray;
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
class US2400Protocol;
|
||||
|
||||
namespace US2400
|
||||
{
|
||||
|
||||
class MackieButtonHandler;
|
||||
class SurfacePort;
|
||||
class MackieMidiBuilder;
|
||||
class Button;
|
||||
class Meter;
|
||||
class Fader;
|
||||
class Jog;
|
||||
class Pot;
|
||||
class Led;
|
||||
|
||||
class Surface : public PBD::ScopedConnectionList, public sigc::trackable
|
||||
{
|
||||
public:
|
||||
Surface (US2400Protocol&, const std::string& name, uint32_t number, surface_type_t stype);
|
||||
virtual ~Surface();
|
||||
|
||||
surface_type_t type() const { return _stype; }
|
||||
uint32_t number() const { return _number; }
|
||||
const std::string& name() { return _name; }
|
||||
|
||||
void connected ();
|
||||
|
||||
bool active() const { return _active; }
|
||||
|
||||
typedef std::vector<Control*> Controls;
|
||||
Controls controls;
|
||||
|
||||
std::map<int,Fader*> faders;
|
||||
std::map<int,Pot*> pots;
|
||||
std::map<int,Button*> buttons; // index is device-DEPENDENT
|
||||
std::map<int,Led*> leds;
|
||||
std::map<int,Meter*> meters;
|
||||
std::map<int,Control*> controls_by_device_independent_id;
|
||||
|
||||
US2400::JogWheel* jog_wheel() const { return _jog_wheel; }
|
||||
Fader* master_fader() const { return _master_fader; }
|
||||
|
||||
/// The collection of all numbered strips.
|
||||
typedef std::vector<Strip*> Strips;
|
||||
Strips strips;
|
||||
|
||||
uint32_t n_strips (bool with_locked_strips = true) const;
|
||||
Strip* nth_strip (uint32_t n) const;
|
||||
|
||||
bool stripable_is_locked_to_strip (boost::shared_ptr<ARDOUR::Stripable>) const;
|
||||
bool stripable_is_mapped (boost::shared_ptr<ARDOUR::Stripable>) const;
|
||||
|
||||
/// This collection owns the groups
|
||||
typedef std::map<std::string,Group*> Groups;
|
||||
Groups groups;
|
||||
|
||||
SurfacePort& port() const { return *_port; }
|
||||
|
||||
void map_stripables (const std::vector<boost::shared_ptr<ARDOUR::Stripable> >&);
|
||||
|
||||
void update_strip_selection ();
|
||||
|
||||
const MidiByteArray& sysex_hdr() const;
|
||||
|
||||
void periodic (ARDOUR::microseconds_t now_usecs);
|
||||
void redisplay (ARDOUR::microseconds_t now_usecs, bool force);
|
||||
void hui_heartbeat ();
|
||||
|
||||
void handle_midi_pitchbend_message (MIDI::Parser&, MIDI::pitchbend_t, uint32_t channel_id);
|
||||
void handle_midi_controller_message (MIDI::Parser&, MIDI::EventTwoBytes*);
|
||||
void handle_midi_note_on_message (MIDI::Parser&, MIDI::EventTwoBytes*);
|
||||
|
||||
/// Connect the any signal from the parser to handle_midi_any
|
||||
/// unless it's already connected
|
||||
void connect_to_signals ();
|
||||
|
||||
/// write a sysex message
|
||||
void write_sysex (const MidiByteArray& mba);
|
||||
void write_sysex (MIDI::byte msg);
|
||||
/// proxy write for port
|
||||
void write (const MidiByteArray&);
|
||||
|
||||
/// display an indicator of the first switched-in Route. Do nothing by default.
|
||||
void display_bank_start (uint32_t /*current_bank*/);
|
||||
|
||||
/// called from US2400Protocol::zero_all to turn things off
|
||||
void zero_all ();
|
||||
void zero_controls ();
|
||||
|
||||
/// turn off leds around the jog wheel. This is for surfaces that use a pot
|
||||
/// pretending to be a jog wheel.
|
||||
void blank_jog_ring ();
|
||||
|
||||
/// sends MCP "reset" message to surface
|
||||
void reset ();
|
||||
|
||||
void recalibrate_faders ();
|
||||
void toggle_backlight ();
|
||||
void set_touch_sensitivity (int);
|
||||
|
||||
/**
|
||||
This is used to calculate the clicks per second that define
|
||||
a transport speed of 1.0 for the jog wheel. 100.0 is 10 clicks
|
||||
per second, 50.5 is 5 clicks per second.
|
||||
*/
|
||||
float scrub_scaling_factor() const;
|
||||
|
||||
/**
|
||||
The scaling factor function for speed increase and decrease. At
|
||||
low transport speeds this should return a small value, for high transport
|
||||
speeds, this should return an exponentially larger value. This provides
|
||||
high definition control at low speeds and quick speed changes to/from
|
||||
higher speeds.
|
||||
*/
|
||||
float scaled_delta (float delta, float current_speed);
|
||||
|
||||
void subview_mode_changed ();
|
||||
|
||||
US2400Protocol& mcp() const { return _mcp; }
|
||||
|
||||
void next_jog_mode ();
|
||||
void set_jog_mode (US2400::JogWheel::Mode);
|
||||
|
||||
void notify_metering_state_changed();
|
||||
void turn_it_on ();
|
||||
|
||||
bool connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool);
|
||||
|
||||
void master_monitor_may_have_changed ();
|
||||
|
||||
XMLNode& get_state ();
|
||||
int set_state (const XMLNode&, int version);
|
||||
|
||||
private:
|
||||
US2400Protocol& _mcp;
|
||||
SurfacePort* _port;
|
||||
surface_type_t _stype;
|
||||
uint32_t _number;
|
||||
std::string _name;
|
||||
bool _active;
|
||||
bool _connected;
|
||||
US2400::JogWheel* _jog_wheel;
|
||||
Fader* _master_fader;
|
||||
float _last_master_gain_written;
|
||||
PBD::ScopedConnection master_connection;
|
||||
|
||||
void handle_midi_sysex (MIDI::Parser&, MIDI::byte *, size_t count);
|
||||
MidiByteArray host_connection_query (MidiByteArray& bytes);
|
||||
MidiByteArray host_connection_confirmation (const MidiByteArray& bytes);
|
||||
|
||||
void say_hello ();
|
||||
void init_controls ();
|
||||
void init_strips (uint32_t n);
|
||||
void setup_master ();
|
||||
void master_gain_changed ();
|
||||
|
||||
enum ConnectionState {
|
||||
InputConnected = 0x1,
|
||||
OutputConnected = 0x2
|
||||
};
|
||||
|
||||
int connection_state;
|
||||
|
||||
public:
|
||||
/* IP MIDI devices need to keep a handle on this and destroy it */
|
||||
GSource* input_source;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
201
libs/surfaces/us2400/surface_port.cc
Normal file
201
libs/surfaces/us2400/surface_port.cc
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
|
||||
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 <sstream>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
|
||||
#include <sigc++/sigc++.h>
|
||||
#include <boost/shared_array.hpp>
|
||||
|
||||
#include "pbd/failed_constructor.h"
|
||||
|
||||
#include "midi++/types.h"
|
||||
|
||||
#include "ardour/async_midi_port.h"
|
||||
#include "ardour/debug.h"
|
||||
#include "ardour/rc_configuration.h"
|
||||
#include "ardour/session.h"
|
||||
#include "ardour/audioengine.h"
|
||||
|
||||
#include "controls.h"
|
||||
#include "us2400_control_protocol.h"
|
||||
#include "surface.h"
|
||||
#include "surface_port.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace PBD;
|
||||
using namespace ARDOUR;
|
||||
using namespace ArdourSurface;
|
||||
using namespace US2400;
|
||||
|
||||
SurfacePort::SurfacePort (Surface& s)
|
||||
: _surface (&s)
|
||||
{
|
||||
string in_name;
|
||||
string out_name;
|
||||
|
||||
in_name = string_compose (X_("US-2400 In #%1"), (_surface->number() + 1));
|
||||
out_name = string_compose (X_("US-2400 Out #%1"), _surface->number() + 1);
|
||||
|
||||
_async_in = AudioEngine::instance()->register_input_port (DataType::MIDI, in_name, true);
|
||||
_async_out = AudioEngine::instance()->register_output_port (DataType::MIDI, out_name, 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();
|
||||
}
|
||||
|
||||
SurfacePort::~SurfacePort()
|
||||
{
|
||||
if (_async_in) {
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("unregistering input port %1\n", _async_in->name()));
|
||||
Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock());
|
||||
AudioEngine::instance()->unregister_port (_async_in);
|
||||
_async_in.reset ((ARDOUR::Port*) 0);
|
||||
}
|
||||
|
||||
if (_async_out) {
|
||||
_output_port->drain (10000, 250000);
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("unregistering output port %1\n", _async_out->name()));
|
||||
Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock());
|
||||
AudioEngine::instance()->unregister_port (_async_out);
|
||||
_async_out.reset ((ARDOUR::Port*) 0);
|
||||
}
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
SurfacePort::get_state ()
|
||||
{
|
||||
XMLNode* node = new XMLNode (X_("Port"));
|
||||
|
||||
XMLNode* child;
|
||||
|
||||
child = new XMLNode (X_("Input"));
|
||||
child->add_child_nocopy (_async_in->get_state());
|
||||
node->add_child_nocopy (*child);
|
||||
|
||||
|
||||
child = new XMLNode (X_("Output"));
|
||||
child->add_child_nocopy (_async_out->get_state());
|
||||
node->add_child_nocopy (*child);
|
||||
|
||||
return *node;
|
||||
}
|
||||
|
||||
int
|
||||
SurfacePort::set_state (const XMLNode& node, int version)
|
||||
{
|
||||
XMLNode* child;
|
||||
|
||||
if ((child = node.child (X_("Input"))) != 0) {
|
||||
XMLNode* portnode = child->child (Port::state_node_name.c_str());
|
||||
if (portnode) {
|
||||
_async_in->set_state (*portnode, version);
|
||||
}
|
||||
}
|
||||
|
||||
if ((child = node.child (X_("Output"))) != 0) {
|
||||
XMLNode* portnode = child->child (Port::state_node_name.c_str());
|
||||
if (portnode) {
|
||||
_async_out->set_state (*portnode, version);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SurfacePort::reconnect ()
|
||||
{
|
||||
_async_out->reconnect ();
|
||||
_async_in->reconnect ();
|
||||
}
|
||||
|
||||
std::string
|
||||
SurfacePort::input_name () const
|
||||
{
|
||||
return _async_in->name();
|
||||
}
|
||||
|
||||
std::string
|
||||
SurfacePort::output_name () const
|
||||
{
|
||||
return _async_out->name();
|
||||
}
|
||||
|
||||
// wrapper for one day when strerror_r is working properly
|
||||
string fetch_errmsg (int error_number)
|
||||
{
|
||||
char * msg = strerror (error_number);
|
||||
return msg;
|
||||
}
|
||||
|
||||
int
|
||||
SurfacePort::write (const MidiByteArray & mba)
|
||||
{
|
||||
if (mba.empty()) {
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("port %1 asked to write an empty MBA\n", output_port().name()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUG_TRACE (DEBUG::US2400, string_compose ("port %1 write %2\n", output_port().name(), mba));
|
||||
|
||||
if (mba[0] != 0xf0 && mba.size() > 3) {
|
||||
std::cerr << "TOO LONG WRITE: " << mba << std::endl;
|
||||
}
|
||||
|
||||
/* this call relies on std::vector<T> using contiguous storage. not
|
||||
* actually guaranteed by the standard, but way, way beyond likely.
|
||||
*/
|
||||
|
||||
int count = output_port().write (&mba[0], mba.size(), 0);
|
||||
|
||||
if (count != (int) mba.size()) {
|
||||
|
||||
if (errno == 0) {
|
||||
|
||||
cout << "port overflow on " << output_port().name() << ". Did not write all of " << mba << endl;
|
||||
|
||||
} else if (errno != EAGAIN) {
|
||||
ostringstream os;
|
||||
os << "Surface: couldn't write to port " << output_port().name();
|
||||
os << ", error: " << fetch_errmsg (errno) << "(" << errno << ")";
|
||||
cout << os.str() << endl;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ostream &
|
||||
US2400::operator << (ostream & os, const SurfacePort & port)
|
||||
{
|
||||
os << "{ ";
|
||||
os << "name: " << port.input_port().name() << " " << port.output_port().name();
|
||||
os << "; ";
|
||||
os << " }";
|
||||
return os;
|
||||
}
|
||||
91
libs/surfaces/us2400/surface_port.h
Normal file
91
libs/surfaces/us2400/surface_port.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
|
||||
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 surface_port_h
|
||||
#define surface_port_h
|
||||
|
||||
#include <midi++/types.h>
|
||||
|
||||
#include "pbd/signals.h"
|
||||
|
||||
|
||||
#include "midi_byte_array.h"
|
||||
#include "types.h"
|
||||
|
||||
namespace MIDI {
|
||||
class Parser;
|
||||
class Port;
|
||||
}
|
||||
|
||||
|
||||
namespace ARDOUR {
|
||||
class AsyncMIDIPort;
|
||||
class Port;
|
||||
}
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
class US2400Protocol;
|
||||
|
||||
namespace US2400
|
||||
{
|
||||
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
Make a relationship between a midi port and a Mackie device.
|
||||
*/
|
||||
|
||||
class SurfacePort
|
||||
{
|
||||
public:
|
||||
SurfacePort (US2400::Surface&);
|
||||
virtual ~SurfacePort();
|
||||
|
||||
/// an easier way to output bytes via midi
|
||||
int write (const MidiByteArray&);
|
||||
|
||||
MIDI::Port& input_port() const { return *_input_port; }
|
||||
MIDI::Port& output_port() const { return *_output_port; }
|
||||
|
||||
ARDOUR::Port& input() const { return *_async_in; }
|
||||
ARDOUR::Port& output() const { return *_async_out; }
|
||||
|
||||
std::string input_name() const;
|
||||
std::string output_name() const;
|
||||
|
||||
void reconnect ();
|
||||
|
||||
XMLNode& get_state ();
|
||||
int set_state (const XMLNode&, int version);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
US2400::Surface* _surface;
|
||||
MIDI::Port* _input_port;
|
||||
MIDI::Port* _output_port;
|
||||
boost::shared_ptr<ARDOUR::Port> _async_in;
|
||||
boost::shared_ptr<ARDOUR::Port> _async_out;
|
||||
};
|
||||
|
||||
std::ostream& operator << (std::ostream& , const SurfacePort& port);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
25
libs/surfaces/us2400/test.cc
Normal file
25
libs/surfaces/us2400/test.cc
Normal file
@@ -0,0 +1,25 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
|
||||
#include "midi_byte_array.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace MIDI {
|
||||
typedef unsigned char byte;
|
||||
byte sysex = 0xf0;
|
||||
byte eox = 0xf7;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
MidiByteArray bytes( 4, 0xf0, 0x01, 0x03, 0x7f );
|
||||
cout << bytes << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
104
libs/surfaces/us2400/timer.h
Normal file
104
libs/surfaces/us2400/timer.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright (C) 1998, 1999, 2000, 2007 John Anderson
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library 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 Library General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef timer_h
|
||||
#define timer_h
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400
|
||||
{
|
||||
|
||||
/**
|
||||
millisecond timer class.
|
||||
*/
|
||||
class Timer
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
start the timer running if true, or just create the
|
||||
object if false.
|
||||
*/
|
||||
Timer( bool shouldStart = true )
|
||||
{
|
||||
if ( shouldStart )
|
||||
start();
|
||||
}
|
||||
|
||||
/**
|
||||
Start the timer running. Return the current timestamp, in milliseconds
|
||||
*/
|
||||
unsigned long start()
|
||||
{
|
||||
_start = g_get_monotonic_time();
|
||||
return _start / 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
returns the number of milliseconds since start
|
||||
also stops the timer running
|
||||
*/
|
||||
unsigned long stop()
|
||||
{
|
||||
_stop = g_get_monotonic_time();
|
||||
return elapsed();
|
||||
}
|
||||
|
||||
/**
|
||||
returns the number of milliseconds since start
|
||||
*/
|
||||
unsigned long elapsed() const
|
||||
{
|
||||
if ( running )
|
||||
{
|
||||
uint64_t now = g_get_monotonic_time();
|
||||
return (now - _start) / 1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (_stop - _start) / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Call stop and then start. Return the value from stop.
|
||||
*/
|
||||
unsigned long restart()
|
||||
{
|
||||
unsigned long retval = stop();
|
||||
start();
|
||||
return retval;
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t _start;
|
||||
uint64_t _stop;
|
||||
bool running;
|
||||
};
|
||||
|
||||
} // US2400 namespace
|
||||
} // ArdourSurface namespace
|
||||
|
||||
#endif
|
||||
51
libs/surfaces/us2400/types.cc
Normal file
51
libs/surfaces/us2400/types.cc
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
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 "types.h"
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
|
||||
LedState on( LedState::on );
|
||||
LedState off( LedState::off );
|
||||
LedState flashing( LedState::flashing );
|
||||
LedState none( LedState::none );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream & operator << ( std::ostream & os, const ArdourSurface::US2400::ControlState & cs )
|
||||
{
|
||||
os << "ControlState { ";
|
||||
os << "pos: " << cs.pos;
|
||||
os << ", ";
|
||||
os << "sign: " << cs.sign;
|
||||
os << ", ";
|
||||
os << "delta: " << cs.delta;
|
||||
os << ", ";
|
||||
os << "ticks: " << cs.ticks;
|
||||
os << ", ";
|
||||
os << "led_state: " << cs.led_state.state();
|
||||
os << ", ";
|
||||
os << "button_state: " << cs.button_state;
|
||||
os << " }";
|
||||
|
||||
return os;
|
||||
}
|
||||
115
libs/surfaces/us2400/types.h
Normal file
115
libs/surfaces/us2400/types.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
|
||||
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 mackie_types_h
|
||||
#define mackie_types_h
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace ArdourSurface {
|
||||
namespace US2400 {
|
||||
|
||||
enum surface_type_t {
|
||||
st_mcu,
|
||||
st_ext,
|
||||
st_joy,
|
||||
st_knb,
|
||||
};
|
||||
|
||||
/**
|
||||
This started off as an enum, but it got really annoying
|
||||
typing ? on : off
|
||||
*/
|
||||
class LedState
|
||||
{
|
||||
public:
|
||||
enum state_t { none, off, flashing, on };
|
||||
LedState() : _state (none) {}
|
||||
LedState (bool yn): _state (yn ? on : off) {}
|
||||
LedState (state_t state): _state (state) {}
|
||||
|
||||
LedState& operator= (state_t s) { _state = s; return *this; }
|
||||
|
||||
bool operator == (const LedState & other) const
|
||||
{
|
||||
return state() == other.state();
|
||||
}
|
||||
|
||||
bool operator != (const LedState & other) const
|
||||
{
|
||||
return state() != other.state();
|
||||
}
|
||||
|
||||
state_t state() const { return _state; }
|
||||
|
||||
private:
|
||||
state_t _state;
|
||||
};
|
||||
|
||||
extern LedState on;
|
||||
extern LedState off;
|
||||
extern LedState flashing;
|
||||
extern LedState none;
|
||||
|
||||
enum ButtonState { neither = -1, release = 0, press = 1 };
|
||||
|
||||
/**
|
||||
Contains the state for a control, with some convenience
|
||||
constructors
|
||||
*/
|
||||
struct ControlState
|
||||
{
|
||||
ControlState(): pos(0.0), sign(0), delta(0.0), ticks(0), led_state(off), button_state(neither) {}
|
||||
|
||||
ControlState (LedState ls): pos(0.0), delta(0.0), led_state(ls), button_state(neither) {}
|
||||
|
||||
// Note that this sets both pos and delta to the flt value
|
||||
ControlState (LedState ls, float flt): pos(flt), delta(flt), ticks(0), led_state(ls), button_state(neither) {}
|
||||
ControlState (float flt): pos(flt), delta(flt), ticks(0), led_state(none), button_state(neither) {}
|
||||
ControlState (float flt, unsigned int tcks): pos(flt), delta(flt), ticks(tcks), led_state(none), button_state(neither) {}
|
||||
ControlState (ButtonState bs): pos(0.0), delta(0.0), ticks(0), led_state(none), button_state(bs) {}
|
||||
|
||||
/// For faders. Between 0 and 1.
|
||||
float pos;
|
||||
|
||||
/// For pots. Sign. Either -1 or 1;
|
||||
int sign;
|
||||
|
||||
/// For pots. Signed value of total movement. Between 0 and 1
|
||||
float delta;
|
||||
|
||||
/// For pots. Unsigned number of ticks. Usually between 1 and 16.
|
||||
unsigned int ticks;
|
||||
|
||||
LedState led_state;
|
||||
ButtonState button_state;
|
||||
};
|
||||
|
||||
std::ostream & operator << (std::ostream &, const ControlState &);
|
||||
|
||||
class Control;
|
||||
class Fader;
|
||||
class Button;
|
||||
class Strip;
|
||||
class Group;
|
||||
class Pot;
|
||||
class Led;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
48
libs/surfaces/us2400/us2400_control_exception.h
Normal file
48
libs/surfaces/us2400/us2400_control_exception.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
|
||||
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 us2400_control_exception_h
|
||||
#define us2400_control_exception_h
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace ArdourSurface {
|
||||
namespace US2400 {
|
||||
|
||||
class MackieControlException : public std::exception
|
||||
{
|
||||
public:
|
||||
MackieControlException( const std::string & msg )
|
||||
: _msg( msg )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~MackieControlException() throw () {}
|
||||
|
||||
const char * what() const throw ()
|
||||
{
|
||||
return _msg.c_str();
|
||||
}
|
||||
|
||||
private:
|
||||
std::string _msg;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
1941
libs/surfaces/us2400/us2400_control_protocol.cc
Normal file
1941
libs/surfaces/us2400/us2400_control_protocol.cc
Normal file
File diff suppressed because it is too large
Load Diff
480
libs/surfaces/us2400/us2400_control_protocol.h
Normal file
480
libs/surfaces/us2400/us2400_control_protocol.h
Normal file
@@ -0,0 +1,480 @@
|
||||
/*
|
||||
Copyright (C) 2006,2007 John Anderson
|
||||
|
||||
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_us2400_control_protocol_h
|
||||
#define ardour_us2400_control_protocol_h
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <pthread.h>
|
||||
#include <boost/smart_ptr.hpp>
|
||||
|
||||
#define ABSTRACT_UI_EXPORTS
|
||||
#include "pbd/abstract_ui.h"
|
||||
#include "midi++/types.h"
|
||||
#include "ardour/types.h"
|
||||
#include "control_protocol/control_protocol.h"
|
||||
|
||||
#include "types.h"
|
||||
#include "midi_byte_array.h"
|
||||
#include "controls.h"
|
||||
#include "jog_wheel.h"
|
||||
#include "timer.h"
|
||||
#include "device_info.h"
|
||||
#include "device_profile.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class AutomationControl;
|
||||
class Port;
|
||||
}
|
||||
|
||||
namespace MIDI {
|
||||
class Port;
|
||||
}
|
||||
|
||||
namespace ArdourSurface {
|
||||
|
||||
namespace US2400 {
|
||||
class Surface;
|
||||
class Control;
|
||||
class SurfacePort;
|
||||
class Button;
|
||||
class Strip;
|
||||
}
|
||||
|
||||
struct US2400ControlUIRequest : public BaseUI::BaseRequestObject {
|
||||
public:
|
||||
US2400ControlUIRequest () {}
|
||||
~US2400ControlUIRequest () {}
|
||||
};
|
||||
|
||||
class US2400Protocol
|
||||
: public ARDOUR::ControlProtocol
|
||||
, public AbstractUI<US2400ControlUIRequest>
|
||||
{
|
||||
public:
|
||||
static const int MODIFIER_OPTION;
|
||||
static const int MODIFIER_CONTROL;
|
||||
static const int MODIFIER_SHIFT;
|
||||
static const int MODIFIER_CMDALT;
|
||||
static const int MODIFIER_ZOOM;
|
||||
static const int MODIFIER_SCRUB;
|
||||
static const int MODIFIER_MARKER;
|
||||
static const int MODIFIER_DROP; //US2400 replaces MODIFIER_NUDGE which is unused
|
||||
static const int MAIN_MODIFIER_MASK;
|
||||
|
||||
enum ViewMode {
|
||||
Mixer,
|
||||
Busses,
|
||||
};
|
||||
|
||||
enum SubViewMode {
|
||||
None,
|
||||
TrackView,
|
||||
};
|
||||
|
||||
US2400Protocol(ARDOUR::Session &);
|
||||
virtual ~US2400Protocol();
|
||||
|
||||
static US2400Protocol* instance() { return _instance; }
|
||||
|
||||
const US2400::DeviceInfo& device_info() const { return _device_info; }
|
||||
US2400::DeviceProfile& device_profile() { return _device_profile; }
|
||||
|
||||
PBD::Signal0<void> DeviceChanged;
|
||||
PBD::Signal1<void,boost::shared_ptr<US2400::Surface> > ConnectionChange;
|
||||
|
||||
void device_ready ();
|
||||
|
||||
int set_active (bool yn);
|
||||
int set_device (const std::string&, bool force);
|
||||
void set_profile (const std::string&);
|
||||
|
||||
ViewMode view_mode () const { return _view_mode; }
|
||||
SubViewMode subview_mode () const { return _subview_mode; }
|
||||
static bool subview_mode_would_be_ok (SubViewMode, boost::shared_ptr<ARDOUR::Stripable>);
|
||||
boost::shared_ptr<ARDOUR::Stripable> subview_stripable() const;
|
||||
bool zoom_mode () const { return modifier_state() & MODIFIER_ZOOM; }
|
||||
bool metering_active () const { return _metering_active; }
|
||||
|
||||
bool is_track (boost::shared_ptr<ARDOUR::Stripable>) const;
|
||||
bool is_audio_track (boost::shared_ptr<ARDOUR::Stripable>) const;
|
||||
bool is_midi_track (boost::shared_ptr<ARDOUR::Stripable>) const;
|
||||
bool is_mapped (boost::shared_ptr<ARDOUR::Stripable>) const;
|
||||
boost::shared_ptr<ARDOUR::Stripable> first_selected_stripable () const;
|
||||
|
||||
void check_fader_automation_state ();
|
||||
void update_fader_automation_state ();
|
||||
void set_automation_state (ARDOUR::AutoState);
|
||||
|
||||
void set_view_mode (ViewMode);
|
||||
int set_subview_mode (SubViewMode, boost::shared_ptr<ARDOUR::Stripable>);
|
||||
void display_view_mode ();
|
||||
|
||||
XMLNode& get_state ();
|
||||
int set_state (const XMLNode&, int version);
|
||||
|
||||
/* Note: because Mackie control is inherently a duplex protocol,
|
||||
we do not implement get/set_feedback() since this aspect of
|
||||
support for the protocol is not optional.
|
||||
*/
|
||||
|
||||
static bool probe();
|
||||
static void* request_factory (uint32_t);
|
||||
|
||||
mutable Glib::Threads::Mutex surfaces_lock;
|
||||
typedef std::list<boost::shared_ptr<US2400::Surface> > Surfaces;
|
||||
Surfaces surfaces;
|
||||
|
||||
boost::shared_ptr<US2400::Surface> get_surface_by_raw_pointer (void*) const;
|
||||
boost::shared_ptr<US2400::Surface> nth_surface (uint32_t) const;
|
||||
|
||||
uint32_t global_index (US2400::Strip&);
|
||||
uint32_t global_index_locked (US2400::Strip&);
|
||||
|
||||
std::list<boost::shared_ptr<ARDOUR::Bundle> > bundles ();
|
||||
|
||||
void set_master_on_surface_strip (uint32_t surface, uint32_t strip);
|
||||
void set_monitor_on_surface_strip (uint32_t surface, uint32_t strip);
|
||||
|
||||
uint32_t n_strips (bool with_locked_strips = true) const;
|
||||
|
||||
bool has_editor () const { return true; }
|
||||
void* get_gui () const;
|
||||
void tear_down_gui ();
|
||||
|
||||
void handle_button_event (US2400::Surface&, US2400::Button& button, US2400::ButtonState);
|
||||
|
||||
void notify_subview_stripable_deleted ();
|
||||
void notify_stripable_removed ();
|
||||
void notify_routes_added (ARDOUR::RouteList &);
|
||||
void notify_vca_added (ARDOUR::VCAList &);
|
||||
|
||||
void notify_presentation_info_changed(PBD::PropertyChange const &);
|
||||
|
||||
void recalibrate_faders ();
|
||||
void toggle_backlight ();
|
||||
void set_touch_sensitivity (int);
|
||||
|
||||
/// rebuild the current bank. Called on route or vca added/removed and
|
||||
/// presentation info changed.
|
||||
void refresh_current_bank();
|
||||
|
||||
// button-related signals
|
||||
void notify_record_state_changed();
|
||||
void notify_transport_state_changed();
|
||||
void notify_loop_state_changed();
|
||||
void notify_metering_state_changed();
|
||||
// mainly to pick up punch-in and punch-out
|
||||
void notify_parameter_changed(std::string const &);
|
||||
void notify_solo_active_changed(bool);
|
||||
|
||||
/// Turn timecode on and beats off, or vice versa, depending
|
||||
/// on state of _timecode_type
|
||||
void update_timecode_beats_led();
|
||||
|
||||
/// this is called to generate the midi to send in response to a button press.
|
||||
void update_led(US2400::Surface&, US2400::Button & button, US2400::LedState);
|
||||
|
||||
void update_global_button (int id, US2400::LedState);
|
||||
void update_global_led (int id, US2400::LedState);
|
||||
|
||||
ARDOUR::Session & get_session() { return *session; }
|
||||
samplepos_t transport_frame() const;
|
||||
|
||||
int modifier_state() const { return _modifier_state; }
|
||||
int main_modifier_state() const { return _modifier_state & MAIN_MODIFIER_MASK; }
|
||||
|
||||
typedef std::list<boost::shared_ptr<ARDOUR::AutomationControl> > ControlList;
|
||||
|
||||
void add_down_button (ARDOUR::AutomationType, int surface, int strip);
|
||||
void remove_down_button (ARDOUR::AutomationType, int surface, int strip);
|
||||
ControlList down_controls (ARDOUR::AutomationType, uint32_t pressed);
|
||||
|
||||
void add_down_select_button (int surface, int strip);
|
||||
void remove_down_select_button (int surface, int strip);
|
||||
void select_range (uint32_t pressed);
|
||||
|
||||
protected:
|
||||
// shut down the surface
|
||||
void close();
|
||||
|
||||
// This sets up the notifications and sets the
|
||||
// controls to the correct values
|
||||
void update_surfaces();
|
||||
|
||||
// connects global (not strip) signals from the Session to here
|
||||
// so the surface can be notified of changes from the other UIs.
|
||||
void connect_session_signals();
|
||||
|
||||
// set all controls to their zero position
|
||||
void zero_all();
|
||||
|
||||
/**
|
||||
Fetch the set of Stripables to be considered for control by the
|
||||
surface. Excluding master, hidden and control routes, and inactive routes
|
||||
*/
|
||||
typedef std::vector<boost::shared_ptr<ARDOUR::Stripable> > Sorted;
|
||||
Sorted get_sorted_stripables();
|
||||
|
||||
// bank switching
|
||||
int switch_banks (uint32_t first_remote_id, bool force = false);
|
||||
void prev_track ();
|
||||
void next_track ();
|
||||
|
||||
void do_request (US2400ControlUIRequest*);
|
||||
int stop ();
|
||||
|
||||
void thread_init ();
|
||||
|
||||
bool stripable_is_locked_to_strip (boost::shared_ptr<ARDOUR::Stripable>) const;
|
||||
|
||||
private:
|
||||
|
||||
struct ButtonHandlers {
|
||||
US2400::LedState (US2400Protocol::*press) (US2400::Button&);
|
||||
US2400::LedState (US2400Protocol::*release) (US2400::Button&);
|
||||
|
||||
ButtonHandlers (US2400::LedState (US2400Protocol::*p) (US2400::Button&),
|
||||
US2400::LedState (US2400Protocol::*r) (US2400::Button&))
|
||||
: press (p)
|
||||
, release (r) {}
|
||||
};
|
||||
|
||||
typedef std::map<US2400::Button::ID,ButtonHandlers> ButtonMap;
|
||||
|
||||
static US2400Protocol* _instance;
|
||||
|
||||
bool profile_exists (std::string const&) const;
|
||||
|
||||
US2400::DeviceInfo _device_info;
|
||||
US2400::DeviceProfile _device_profile;
|
||||
sigc::connection periodic_connection;
|
||||
sigc::connection redisplay_connection;
|
||||
sigc::connection hui_connection;
|
||||
uint32_t _current_initial_bank;
|
||||
PBD::ScopedConnectionList audio_engine_connections;
|
||||
PBD::ScopedConnectionList session_connections;
|
||||
PBD::ScopedConnectionList stripable_connections;
|
||||
PBD::ScopedConnectionList subview_stripable_connections;
|
||||
PBD::ScopedConnectionList gui_connections;
|
||||
// timer for two quick marker left presses
|
||||
US2400::Timer _frm_left_last;
|
||||
// last written timecode string
|
||||
std::string _timecode_last;
|
||||
samplepos_t _frame_last;
|
||||
// Which timecode are we displaying? BBT or Timecode
|
||||
ARDOUR::AnyTime::Type _timecode_type;
|
||||
// Bundle to represent our input ports
|
||||
boost::shared_ptr<ARDOUR::Bundle> _input_bundle;
|
||||
// Bundle to represent our output ports
|
||||
boost::shared_ptr<ARDOUR::Bundle> _output_bundle;
|
||||
void* _gui;
|
||||
bool _scrub_mode;
|
||||
ViewMode _view_mode;
|
||||
SubViewMode _subview_mode;
|
||||
boost::shared_ptr<ARDOUR::Stripable> _subview_stripable;
|
||||
int _current_selected_track;
|
||||
int _modifier_state;
|
||||
ButtonMap button_map;
|
||||
bool _metering_active;
|
||||
bool _initialized;
|
||||
XMLNode* configuration_state;
|
||||
int state_version;
|
||||
int _last_bank[9];
|
||||
bool marker_modifier_consumed_by_button;
|
||||
bool nudge_modifier_consumed_by_button;
|
||||
|
||||
boost::shared_ptr<ArdourSurface::US2400::Surface> _master_surface;
|
||||
|
||||
int create_surfaces ();
|
||||
bool periodic();
|
||||
bool redisplay();
|
||||
bool redisplay_subview_mode ();
|
||||
bool hui_heartbeat ();
|
||||
void build_gui ();
|
||||
bool midi_input_handler (Glib::IOCondition ioc, MIDI::Port* port);
|
||||
void clear_ports ();
|
||||
void clear_surfaces ();
|
||||
void force_special_stripable_to_strip (boost::shared_ptr<ARDOUR::Stripable> r, uint32_t surface, uint32_t strip_number);
|
||||
void build_button_map ();
|
||||
void stripable_selection_changed ();
|
||||
void initialize ();
|
||||
int set_device_info (const std::string& device_name);
|
||||
void update_configuration_state ();
|
||||
|
||||
/* MIDI port connection management */
|
||||
|
||||
PBD::ScopedConnection port_connection;
|
||||
void connection_handler (boost::weak_ptr<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, std::string name2, bool);
|
||||
|
||||
/* BUTTON HANDLING */
|
||||
|
||||
typedef std::set<uint32_t> DownButtonList;
|
||||
typedef std::map<ARDOUR::AutomationType,DownButtonList> DownButtonMap;
|
||||
DownButtonMap _down_buttons;
|
||||
DownButtonList _down_select_buttons;
|
||||
|
||||
void pull_stripable_range (DownButtonList&, ARDOUR::StripableList&, uint32_t pressed);
|
||||
|
||||
/* implemented button handlers */
|
||||
US2400::LedState stop_press(US2400::Button &);
|
||||
US2400::LedState stop_release(US2400::Button &);
|
||||
US2400::LedState play_press(US2400::Button &);
|
||||
US2400::LedState play_release(US2400::Button &);
|
||||
US2400::LedState record_press(US2400::Button &);
|
||||
US2400::LedState record_release(US2400::Button &);
|
||||
US2400::LedState loop_press(US2400::Button &);
|
||||
US2400::LedState loop_release(US2400::Button &);
|
||||
US2400::LedState rewind_press(US2400::Button & button);
|
||||
US2400::LedState rewind_release(US2400::Button & button);
|
||||
US2400::LedState ffwd_press(US2400::Button & button);
|
||||
US2400::LedState ffwd_release(US2400::Button & button);
|
||||
US2400::LedState cursor_up_press (US2400::Button &);
|
||||
US2400::LedState cursor_up_release (US2400::Button &);
|
||||
US2400::LedState cursor_down_press (US2400::Button &);
|
||||
US2400::LedState cursor_down_release (US2400::Button &);
|
||||
US2400::LedState cursor_left_press (US2400::Button &);
|
||||
US2400::LedState cursor_left_release (US2400::Button &);
|
||||
US2400::LedState cursor_right_press (US2400::Button &);
|
||||
US2400::LedState cursor_right_release (US2400::Button &);
|
||||
US2400::LedState left_press(US2400::Button &);
|
||||
US2400::LedState left_release(US2400::Button &);
|
||||
US2400::LedState right_press(US2400::Button &);
|
||||
US2400::LedState right_release(US2400::Button &);
|
||||
US2400::LedState channel_left_press(US2400::Button &);
|
||||
US2400::LedState channel_left_release(US2400::Button &);
|
||||
US2400::LedState channel_right_press(US2400::Button &);
|
||||
US2400::LedState channel_right_release(US2400::Button &);
|
||||
US2400::LedState marker_press(US2400::Button &);
|
||||
US2400::LedState marker_release(US2400::Button &);
|
||||
US2400::LedState save_press(US2400::Button &);
|
||||
US2400::LedState save_release(US2400::Button &);
|
||||
US2400::LedState timecode_beats_press(US2400::Button &);
|
||||
US2400::LedState timecode_beats_release(US2400::Button &);
|
||||
US2400::LedState zoom_press(US2400::Button &);
|
||||
US2400::LedState zoom_release(US2400::Button &);
|
||||
US2400::LedState scrub_press(US2400::Button &);
|
||||
US2400::LedState scrub_release(US2400::Button &);
|
||||
US2400::LedState undo_press (US2400::Button &);
|
||||
US2400::LedState undo_release (US2400::Button &);
|
||||
US2400::LedState shift_press (US2400::Button &);
|
||||
US2400::LedState shift_release (US2400::Button &);
|
||||
US2400::LedState option_press (US2400::Button &);
|
||||
US2400::LedState option_release (US2400::Button &);
|
||||
US2400::LedState control_press (US2400::Button &);
|
||||
US2400::LedState control_release (US2400::Button &);
|
||||
US2400::LedState cmd_alt_press (US2400::Button &);
|
||||
US2400::LedState cmd_alt_release (US2400::Button &);
|
||||
|
||||
US2400::LedState pan_press (US2400::Button &);
|
||||
US2400::LedState pan_release (US2400::Button &);
|
||||
US2400::LedState plugin_press (US2400::Button &);
|
||||
US2400::LedState plugin_release (US2400::Button &);
|
||||
US2400::LedState eq_press (US2400::Button &);
|
||||
US2400::LedState eq_release (US2400::Button &);
|
||||
US2400::LedState dyn_press (US2400::Button &);
|
||||
US2400::LedState dyn_release (US2400::Button &);
|
||||
US2400::LedState flip_press (US2400::Button &);
|
||||
US2400::LedState flip_release (US2400::Button &);
|
||||
US2400::LedState name_value_press (US2400::Button &);
|
||||
US2400::LedState name_value_release (US2400::Button &);
|
||||
// US2400::LedState F1_press (US2400::Button &);
|
||||
// US2400::LedState F1_release (US2400::Button &);
|
||||
// US2400::LedState F2_press (US2400::Button &);
|
||||
// US2400::LedState F2_release (US2400::Button &);
|
||||
// US2400::LedState F3_press (US2400::Button &);
|
||||
// US2400::LedState F3_release (US2400::Button &);
|
||||
// US2400::LedState F4_press (US2400::Button &);
|
||||
// US2400::LedState F4_release (US2400::Button &);
|
||||
// US2400::LedState F5_press (US2400::Button &);
|
||||
// US2400::LedState F5_release (US2400::Button &);
|
||||
// US2400::LedState F6_press (US2400::Button &);
|
||||
// US2400::LedState F6_release (US2400::Button &);
|
||||
// US2400::LedState F7_press (US2400::Button &);
|
||||
// US2400::LedState F7_release (US2400::Button &);
|
||||
// US2400::LedState F8_press (US2400::Button &);
|
||||
// US2400::LedState F8_release (US2400::Button &);
|
||||
US2400::LedState touch_press (US2400::Button &);
|
||||
US2400::LedState touch_release (US2400::Button &);
|
||||
US2400::LedState enter_press (US2400::Button &);
|
||||
US2400::LedState enter_release (US2400::Button &);
|
||||
US2400::LedState cancel_press (US2400::Button &);
|
||||
US2400::LedState cancel_release (US2400::Button &);
|
||||
US2400::LedState user_a_press (US2400::Button &);
|
||||
US2400::LedState user_a_release (US2400::Button &);
|
||||
US2400::LedState user_b_press (US2400::Button &);
|
||||
US2400::LedState user_b_release (US2400::Button &);
|
||||
US2400::LedState fader_touch_press (US2400::Button &);
|
||||
US2400::LedState fader_touch_release (US2400::Button &);
|
||||
US2400::LedState master_fader_touch_press (US2400::Button &);
|
||||
US2400::LedState master_fader_touch_release (US2400::Button &);
|
||||
|
||||
US2400::LedState read_press (US2400::Button&);
|
||||
US2400::LedState read_release (US2400::Button&);
|
||||
US2400::LedState write_press (US2400::Button&);
|
||||
US2400::LedState write_release (US2400::Button&);
|
||||
US2400::LedState clearsolo_press (US2400::Button&);
|
||||
US2400::LedState clearsolo_release (US2400::Button&);
|
||||
US2400::LedState track_press (US2400::Button&);
|
||||
US2400::LedState track_release (US2400::Button&);
|
||||
US2400::LedState send_press (US2400::Button&);
|
||||
US2400::LedState send_release (US2400::Button&);
|
||||
US2400::LedState miditracks_press (US2400::Button&);
|
||||
US2400::LedState miditracks_release (US2400::Button&);
|
||||
US2400::LedState inputs_press (US2400::Button&);
|
||||
US2400::LedState inputs_release (US2400::Button&);
|
||||
US2400::LedState audiotracks_press (US2400::Button&);
|
||||
US2400::LedState audiotracks_release (US2400::Button&);
|
||||
US2400::LedState audioinstruments_press (US2400::Button&);
|
||||
US2400::LedState audioinstruments_release (US2400::Button&);
|
||||
US2400::LedState aux_press (US2400::Button&);
|
||||
US2400::LedState aux_release (US2400::Button&);
|
||||
US2400::LedState busses_press (US2400::Button&);
|
||||
US2400::LedState busses_release (US2400::Button&);
|
||||
US2400::LedState outputs_press (US2400::Button&);
|
||||
US2400::LedState outputs_release (US2400::Button&);
|
||||
US2400::LedState user_press (US2400::Button&);
|
||||
US2400::LedState user_release (US2400::Button&);
|
||||
US2400::LedState trim_press (US2400::Button&);
|
||||
US2400::LedState trim_release (US2400::Button&);
|
||||
US2400::LedState latch_press (US2400::Button&);
|
||||
US2400::LedState latch_release (US2400::Button&);
|
||||
US2400::LedState grp_press (US2400::Button&);
|
||||
US2400::LedState grp_release (US2400::Button&);
|
||||
US2400::LedState nudge_press (US2400::Button&);
|
||||
US2400::LedState nudge_release (US2400::Button&);
|
||||
US2400::LedState drop_press (US2400::Button&);
|
||||
US2400::LedState drop_release (US2400::Button&);
|
||||
US2400::LedState replace_press (US2400::Button&);
|
||||
US2400::LedState replace_release (US2400::Button&);
|
||||
US2400::LedState click_press (US2400::Button&);
|
||||
US2400::LedState click_release (US2400::Button&);
|
||||
US2400::LedState view_press (US2400::Button&);
|
||||
US2400::LedState view_release (US2400::Button&);
|
||||
|
||||
US2400::LedState bank_release (US2400::Button&, uint32_t bank_num);
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif // ardour_us2400_control_protocol_h
|
||||
26
libs/surfaces/us2400/us2400_control_protocol_poll.cc
Normal file
26
libs/surfaces/us2400/us2400_control_protocol_poll.cc
Normal file
@@ -0,0 +1,26 @@
|
||||
#include "us2400_control_protocol.h"
|
||||
|
||||
#include "midi_byte_array.h"
|
||||
#include "surface_port.h"
|
||||
|
||||
#include "pbd/pthread_utils.h"
|
||||
#include "pbd/error.h"
|
||||
|
||||
#include "midi++/types.h"
|
||||
#include "midi++/port.h"
|
||||
#include "midi++/manager.h"
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using namespace US2400;
|
||||
using namespace PBD;
|
||||
|
||||
49
libs/surfaces/us2400/wscript
Normal file
49
libs/surfaces/us2400/wscript
Normal file
@@ -0,0 +1,49 @@
|
||||
#!/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 = '''
|
||||
button.cc
|
||||
controls.cc
|
||||
device_info.cc
|
||||
device_profile.cc
|
||||
fader.cc
|
||||
gui.cc
|
||||
interface.cc
|
||||
jog.cc
|
||||
jog_wheel.cc
|
||||
led.cc
|
||||
us2400_control_protocol.cc
|
||||
mcp_buttons.cc
|
||||
meter.cc
|
||||
midi_byte_array.cc
|
||||
pot.cc
|
||||
strip.cc
|
||||
surface.cc
|
||||
surface_port.cc
|
||||
types.cc
|
||||
'''
|
||||
obj.export_includes = ['./us2400']
|
||||
obj.defines = [ 'PACKAGE="ardour_us2400"' ]
|
||||
obj.defines += [ 'ARDOURSURFACE_DLL_EXPORTS' ]
|
||||
obj.includes = [ '.' ]
|
||||
obj.name = 'libardour_us2400'
|
||||
obj.target = 'ardour_us2400'
|
||||
obj.uselib = 'GTKMM XML'
|
||||
obj.use = 'libardour libardour_cp libgtkmm2ext'
|
||||
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
|
||||
|
||||
def shutdown():
|
||||
autowaf.shutdown()
|
||||
Reference in New Issue
Block a user