summaryrefslogtreecommitdiff
path: root/libs/surfaces/mackie
diff options
context:
space:
mode:
Diffstat (limited to 'libs/surfaces/mackie')
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.cc163
-rw-r--r--libs/surfaces/mackie/mackie_control_protocol.h22
-rw-r--r--libs/surfaces/mackie/mcp_buttons.cc30
-rw-r--r--libs/surfaces/mackie/strip.cc622
-rw-r--r--libs/surfaces/mackie/strip.h21
-rw-r--r--libs/surfaces/mackie/subview.cc1233
-rw-r--r--libs/surfaces/mackie/subview.h279
-rw-r--r--libs/surfaces/mackie/subview_modes.h39
-rw-r--r--libs/surfaces/mackie/wscript1
9 files changed, 1664 insertions, 746 deletions
diff --git a/libs/surfaces/mackie/mackie_control_protocol.cc b/libs/surfaces/mackie/mackie_control_protocol.cc
index c558f27837..c2ab8e7fac 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.cc
+++ b/libs/surfaces/mackie/mackie_control_protocol.cc
@@ -72,6 +72,7 @@
#include "midi_byte_array.h"
#include "mackie_control_exception.h"
#include "device_profile.h"
+#include "subview.h"
#include "surface_port.h"
#include "surface.h"
#include "strip.h"
@@ -126,7 +127,7 @@ MackieControlProtocol::MackieControlProtocol (Session& session)
, _scrub_mode (false)
, _flip_mode (Normal)
, _view_mode (Mixer)
- , _subview_mode (None)
+ , _subview (0)
, _current_selected_track (-1)
, _modifier_state (0)
, _ipmidi_base (MIDI::IPMIDIPort::lowest_ipmidi_port_default)
@@ -139,6 +140,8 @@ MackieControlProtocol::MackieControlProtocol (Session& session)
, nudge_modifier_consumed_by_button (false)
{
DEBUG_TRACE (DEBUG::MackieControl, "MackieControlProtocol::MackieControlProtocol\n");
+
+ _subview = Mackie::SubviewFactory::instance()->create_subview(SubViewMode::None, *this, boost::shared_ptr<Stripable>());
DeviceInfo::reload_device_info ();
DeviceProfile::reload_device_profiles ();
@@ -658,7 +661,7 @@ MackieControlProtocol::device_ready ()
{
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("device ready init (active=%1)\n", active()));
update_surfaces ();
- set_subview_mode (MackieControlProtocol::None, boost::shared_ptr<Stripable>());
+ set_subview_mode (Mackie::SubViewMode::None, boost::shared_ptr<Stripable>());
set_flip_mode (Normal);
}
@@ -1697,46 +1700,11 @@ void
MackieControlProtocol::notify_subview_stripable_deleted ()
{
/* return to global/mixer view */
- _subview_stripable.reset ();
+ _subview->notify_subview_stripable_deleted();
set_view_mode (Mixer);
}
bool
-MackieControlProtocol::subview_mode_would_be_ok (SubViewMode mode, boost::shared_ptr<Stripable> r)
-{
- switch (mode) {
- case None:
- return true;
- break;
-
- case Sends:
- if (r && r->send_level_controllable (0)) {
- return true;
- }
- break;
-
- case EQ:
- if (r && r->eq_band_cnt() > 0) {
- return true;
- }
- break;
-
- case Dynamics:
- if (r && r->comp_enable_controllable()) {
- return true;
- }
- break;
-
- case TrackView:
- if (r) {
- return true;
- }
- }
-
- return false;
-}
-
-bool
MackieControlProtocol::redisplay_subview_mode ()
{
Surfaces copy; /* can't hold surfaces lock while calling Strip::subview_mode_changed */
@@ -1754,7 +1722,7 @@ MackieControlProtocol::redisplay_subview_mode ()
return false;
}
-int
+bool
MackieControlProtocol::set_subview_mode (SubViewMode sm, boost::shared_ptr<Stripable> r)
{
DEBUG_TRACE (DEBUG::MackieControl, string_compose ("set subview mode %1 with stripable %2, current flip mode %3\n", sm, (r ? r->name() : string ("null")), _flip_mode));
@@ -1763,7 +1731,8 @@ MackieControlProtocol::set_subview_mode (SubViewMode sm, boost::shared_ptr<Strip
set_flip_mode (Normal);
}
- if (!subview_mode_would_be_ok (sm, r)) {
+ std::string reason_why_subview_not_possible = "";
+ if (!_subview->subview_mode_would_be_ok (sm, r, reason_why_subview_not_possible)) {
DEBUG_TRACE (DEBUG::MackieControl, "subview mode not OK\n");
@@ -1772,27 +1741,9 @@ MackieControlProtocol::set_subview_mode (SubViewMode sm, boost::shared_ptr<Strip
Glib::Threads::Mutex::Lock lm (surfaces_lock);
if (!surfaces.empty()) {
-
- string msg;
-
- switch (sm) {
- case Sends:
- msg = _("no sends for selected track/bus");
- break;
- case EQ:
- msg = _("no EQ in the track/bus");
- break;
- case Dynamics:
- msg = _("no dynamics in selected track/bus");
- break;
- case TrackView:
- msg = _("no track view possible");
- default:
- break;
- }
- if (!msg.empty()) {
- surfaces.front()->display_message_for (msg, 1000);
- if (_subview_mode != None) {
+ if (!reason_why_subview_not_possible.empty()) {
+ surfaces.front()->display_message_for (reason_why_subview_not_possible, 1000);
+ if (_subview->subview_mode() != Mackie::SubViewMode::None) {
/* redisplay current subview mode after
that message goes away.
*/
@@ -1804,73 +1755,21 @@ MackieControlProtocol::set_subview_mode (SubViewMode sm, boost::shared_ptr<Strip
}
}
- return -1;
+ return false;
}
-
- boost::shared_ptr<Stripable> old_stripable = _subview_stripable;
-
- _subview_mode = sm;
- _subview_stripable = r;
-
- if (_subview_stripable != old_stripable) {
- subview_stripable_connections.drop_connections ();
-
- /* Catch the current subview stripable going away */
- if (_subview_stripable) {
- _subview_stripable->DropReferences.connect (subview_stripable_connections, MISSING_INVALIDATOR,
- boost::bind (&MackieControlProtocol::notify_subview_stripable_deleted, this),
- this);
- }
+
+ _subview = Mackie::SubviewFactory::instance()->create_subview(sm, *this, r);
+ /* Catch the current subview stripable going away */
+ if (_subview->subview_stripable()) {
+ _subview->subview_stripable()->DropReferences.connect (_subview->subview_stripable_connections(), MISSING_INVALIDATOR,
+ boost::bind (&MackieControlProtocol::notify_subview_stripable_deleted, this),
+ this);
}
redisplay_subview_mode ();
+ _subview->update_global_buttons();
- /* turn buttons related to vpot mode on or off as required */
-
- switch (_subview_mode) {
- case MackieControlProtocol::None:
- update_global_button (Button::Send, off);
- update_global_button (Button::Plugin, off);
- update_global_button (Button::Eq, off);
- update_global_button (Button::Dyn, off);
- update_global_button (Button::Track, off);
- update_global_button (Button::Pan, on);
- break;
- case MackieControlProtocol::EQ:
- update_global_button (Button::Send, off);
- update_global_button (Button::Plugin, off);
- update_global_button (Button::Eq, on);
- update_global_button (Button::Dyn, off);
- update_global_button (Button::Track, off);
- update_global_button (Button::Pan, off);
- break;
- case MackieControlProtocol::Dynamics:
- update_global_button (Button::Send, off);
- update_global_button (Button::Plugin, off);
- update_global_button (Button::Eq, off);
- update_global_button (Button::Dyn, on);
- update_global_button (Button::Track, off);
- update_global_button (Button::Pan, off);
- break;
- case MackieControlProtocol::Sends:
- update_global_button (Button::Send, on);
- update_global_button (Button::Plugin, off);
- update_global_button (Button::Eq, off);
- update_global_button (Button::Dyn, off);
- update_global_button (Button::Track, off);
- update_global_button (Button::Pan, off);
- break;
- case MackieControlProtocol::TrackView:
- update_global_button (Button::Send, off);
- update_global_button (Button::Plugin, off);
- update_global_button (Button::Eq, off);
- update_global_button (Button::Dyn, off);
- update_global_button (Button::Track, on);
- update_global_button (Button::Pan, off);
- break;
- }
-
- return 0;
+ return true;
}
void
@@ -1890,7 +1789,8 @@ MackieControlProtocol::set_view_mode (ViewMode m)
}
/* leave subview mode, whatever it was */
- set_subview_mode (None, boost::shared_ptr<Stripable>());
+ DEBUG_TRACE (DEBUG::MackieControl, "\t\t\tsubview mode reset in MackieControlProtocol::set_view_mode \n");
+ set_subview_mode (Mackie::SubViewMode::None, boost::shared_ptr<Stripable>());
display_view_mode ();
}
@@ -2445,10 +2345,13 @@ MackieControlProtocol::stripable_selection_changed ()
* set_subview_mode() will fail, and we will reset to None.
*/
- if (set_subview_mode (_subview_mode, s)) {
- set_subview_mode (None, boost::shared_ptr<Stripable>());
+ if (!set_subview_mode (_subview->subview_mode(), s)) {
+ set_subview_mode (Mackie::SubViewMode::None, boost::shared_ptr<Stripable>());
}
-
+ }
+ else {
+ // none selected or not on surface
+ set_subview_mode(Mackie::SubViewMode::None, boost::shared_ptr<Stripable>());
}
}
@@ -2475,12 +2378,6 @@ MackieControlProtocol::first_selected_stripable () const
return s; /* may be null */
}
-boost::shared_ptr<Stripable>
-MackieControlProtocol::subview_stripable () const
-{
- return _subview_stripable;
-}
-
uint32_t
MackieControlProtocol::global_index (Strip& strip)
{
diff --git a/libs/surfaces/mackie/mackie_control_protocol.h b/libs/surfaces/mackie/mackie_control_protocol.h
index 23ae32001e..c80820d07b 100644
--- a/libs/surfaces/mackie/mackie_control_protocol.h
+++ b/libs/surfaces/mackie/mackie_control_protocol.h
@@ -46,6 +46,7 @@
#include "timer.h"
#include "device_info.h"
#include "device_profile.h"
+#include "subview_modes.h"
namespace ARDOUR {
class AutomationControl;
@@ -59,6 +60,7 @@ namespace MIDI {
namespace ArdourSurface {
namespace Mackie {
+ class Subview;
class Surface;
class Control;
class SurfacePort;
@@ -100,14 +102,6 @@ class MackieControlProtocol
Plugins,
};
- enum SubViewMode {
- None,
- EQ,
- Dynamics,
- Sends,
- TrackView,
- };
-
enum FlipMode {
Normal, /* fader controls primary, vpot controls secondary */
Mirror, /* fader + vpot control secondary */
@@ -134,9 +128,7 @@ class MackieControlProtocol
FlipMode flip_mode () const { return _flip_mode; }
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;
+ boost::shared_ptr<Mackie::Subview> subview() { return _subview; }
bool zoom_mode () const { return modifier_state() & MODIFIER_ZOOM; }
bool metering_active () const { return _metering_active; }
@@ -151,7 +143,8 @@ class MackieControlProtocol
void set_automation_state (ARDOUR::AutoState);
void set_view_mode (ViewMode);
- int set_subview_mode (SubViewMode, boost::shared_ptr<ARDOUR::Stripable>);
+ bool set_subview_mode (Mackie::SubViewMode, boost::shared_ptr<ARDOUR::Stripable>);
+ bool redisplay_subview_mode ();
void set_flip_mode (FlipMode);
void display_view_mode ();
@@ -311,7 +304,6 @@ class MackieControlProtocol
PBD::ScopedConnectionList audio_engine_connections;
PBD::ScopedConnectionList session_connections;
PBD::ScopedConnectionList stripable_connections;
- PBD::ScopedConnectionList subview_stripable_connections;
PBD::ScopedConnectionList gui_connections;
PBD::ScopedConnectionList fader_automation_connections;
// timer for two quick marker left presses
@@ -329,8 +321,7 @@ class MackieControlProtocol
bool _scrub_mode;
FlipMode _flip_mode;
ViewMode _view_mode;
- SubViewMode _subview_mode;
- boost::shared_ptr<ARDOUR::Stripable> _subview_stripable;
+ boost::shared_ptr<Mackie::Subview> _subview;
int _current_selected_track;
int _modifier_state;
ButtonMap button_map;
@@ -356,7 +347,6 @@ class MackieControlProtocol
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);
diff --git a/libs/surfaces/mackie/mcp_buttons.cc b/libs/surfaces/mackie/mcp_buttons.cc
index 23ea77c94a..b5244b9df3 100644
--- a/libs/surfaces/mackie/mcp_buttons.cc
+++ b/libs/surfaces/mackie/mcp_buttons.cc
@@ -32,6 +32,7 @@
#include "ardour/rc_configuration.h"
#include "mackie_control_protocol.h"
+#include "subview.h"
#include "surface.h"
#include "fader.h"
@@ -101,7 +102,7 @@ MackieControlProtocol::cmd_alt_release (Button &)
LedState
MackieControlProtocol::left_press (Button &)
{
- if (_subview_mode != None) {
+ if (_subview->subview_mode() != Mackie::SubViewMode::None) {
return none;
}
@@ -129,7 +130,7 @@ MackieControlProtocol::left_release (Button &)
LedState
MackieControlProtocol::right_press (Button &)
{
- if (_subview_mode != None) {
+ if (_subview->subview_mode() != Mackie::SubViewMode::None) {
return none;
}
@@ -159,6 +160,12 @@ MackieControlProtocol::right_release (Button &)
LedState
MackieControlProtocol::cursor_left_press (Button& )
{
+ bool press_handled_by_subview = _subview->handle_cursor_left_press();
+ if (press_handled_by_subview)
+ {
+ return off;
+ }
+
if (zoom_mode()) {
if (main_modifier_state() & MODIFIER_OPTION) {
@@ -193,6 +200,12 @@ MackieControlProtocol::cursor_left_release (Button&)
LedState
MackieControlProtocol::cursor_right_press (Button& )
{
+ bool press_handled_by_subview = _subview->handle_cursor_right_press();
+ if (press_handled_by_subview)
+ {
+ return off;
+ }
+
if (zoom_mode()) {
if (main_modifier_state() & MODIFIER_OPTION) {
@@ -275,7 +288,7 @@ MackieControlProtocol::channel_left_press (Button &)
return on;
}
- if (_subview_mode != None) {
+ if (_subview->subview_mode() != Mackie::SubViewMode::None) {
return none;
}
Sorted sorted = get_sorted_stripables();
@@ -301,7 +314,7 @@ MackieControlProtocol::channel_right_press (Button &)
return on;
}
- if (_subview_mode != None) {
+ if (_subview->subview_mode() != Mackie::SubViewMode::None) {
return none;
}
Sorted sorted = get_sorted_stripables();
@@ -615,7 +628,7 @@ MackieControlProtocol::enter_release (Button &)
LedState
MackieControlProtocol::bank_release (Button& b, uint32_t basic_bank_num)
{
- if (_subview_mode != None) {
+ if (_subview->subview_mode() != Mackie::SubViewMode::None) {
return none;
}
@@ -720,7 +733,7 @@ LedState
MackieControlProtocol::pan_press (Button &)
{
/* XXX eventually pan may have its own subview mode */
- set_subview_mode (MackieControlProtocol::None, boost::shared_ptr<Stripable>());
+ set_subview_mode (Mackie::SubViewMode::None, boost::shared_ptr<Stripable>());
return none;
}
LedState
@@ -731,7 +744,8 @@ MackieControlProtocol::pan_release (Button &)
LedState
MackieControlProtocol::plugin_press (Button &)
{
- return off;
+ set_subview_mode (SubViewMode::Plugin, first_selected_stripable());
+ return none;
}
LedState
MackieControlProtocol::plugin_release (Button &)
@@ -767,7 +781,7 @@ MackieControlProtocol::dyn_release (Button &)
LedState
MackieControlProtocol::flip_press (Button &)
{
- if (subview_mode() == MackieControlProtocol::Sends) {
+ if (_subview->permit_flipping_faders_and_pots()) {
if (_flip_mode != Normal) {
set_flip_mode (Normal);
} else {
diff --git a/libs/surfaces/mackie/strip.cc b/libs/surfaces/mackie/strip.cc
index 7f7e9bbe35..9061eb74de 100644
--- a/libs/surfaces/mackie/strip.cc
+++ b/libs/surfaces/mackie/strip.cc
@@ -59,6 +59,7 @@
#include "ardour/value_as_string.h"
#include "mackie_control_protocol.h"
+#include "subview.h"
#include "surface_port.h"
#include "surface.h"
#include "strip.h"
@@ -108,7 +109,6 @@ Strip::Strip (Surface& s, const std::string& name, int index, const map<Button::
, _metering_active (true)
, _block_screen_redisplay_until (0)
, return_to_vpot_mode_display_at (UINT64_MAX)
- , eq_band (-1)
, _pan_mode (PanAzimuthAutomation)
, _last_gain_position_written (-1.0)
, _last_pan_azi_position_written (-1.0)
@@ -255,7 +255,7 @@ Strip::set_stripable (boost::shared_ptr<Stripable> r, bool /*with_messages*/)
_pan_mode = PanAzimuthAutomation;
- if (_surface->mcp().subview_mode() == MackieControlProtocol::None) {
+ if (_surface->mcp().subview()->subview_mode() == SubViewMode::None) {
set_vpot_parameter (_pan_mode);
}
@@ -394,9 +394,9 @@ Strip::update_selection_state ()
void
Strip::show_stripable_name ()
{
- MackieControlProtocol::SubViewMode svm = _surface->mcp().subview_mode();
+ SubViewMode svm = _surface->mcp().subview()->subview_mode();
- if (svm != MackieControlProtocol::None) {
+ if (svm != SubViewMode::None) {
/* subview mode is responsible for upper line */
return;
}
@@ -416,153 +416,6 @@ Strip::show_stripable_name ()
}
void
-Strip::notify_send_level_change (uint32_t send_num, bool force_update)
-{
- boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
-
- if (!r) {
- /* not in subview mode */
- return;
- }
-
- if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
- /* no longer in Sends subview mode */
- return;
- }
-
- boost::shared_ptr<AutomationControl> control = r->send_level_controllable (send_num);
- if (!control) {
- return;
- }
-
- if (control) {
- float val = control->get_value();
- do_parameter_display (control->desc (), val); // BusSendLevel
-
- if (_vpot->control() == control) {
- /* update pot/encoder */
- _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
- }
- }
-}
-
-void
-Strip::notify_trackview_change (AutomationType type, uint32_t send_num, bool force_update)
-{
- boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
-
- if (!r) {
- /* not in subview mode */
- return;
- }
-
- if (_surface->mcp().subview_mode() != MackieControlProtocol::TrackView) {
- /* no longer in TrackViewsubview mode */
- return;
- }
-
- boost::shared_ptr<AutomationControl> control;
- boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
- bool screen_hold = false;
-
- switch (type) {
- case TrimAutomation:
- control = r->trim_control();
- screen_hold = true;
- break;
- case SoloIsolateAutomation:
- control = r->solo_isolate_control ();
- break;
- case SoloSafeAutomation:
- control = r->solo_safe_control ();
- break;
- case MonitoringAutomation:
- if (track) {
- control = track->monitoring_control();
- screen_hold = true;
- }
- break;
- case PhaseAutomation:
- control = r->phase_control ();
- screen_hold = true;
- break;
- default:
- break;
- }
-
- if (control) {
- float val = control->get_value();
-
- /* Note: all of the displayed controllables require the display
- * of their *actual* ("internal") value, not the version mapped
- * into the normalized 0..1.0 ("interface") range.
- */
-
- do_parameter_display (control->desc(), val, screen_hold);
- /* update pot/encoder */
- _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
- }
-}
-
-void
-Strip::notify_eq_change (boost::weak_ptr<AutomationControl> pc, bool force_update)
-{
- boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
-
- if (!r) {
- /* not in subview mode */
- return;
- }
-
- if (_surface->mcp().subview_mode() != MackieControlProtocol::EQ) {
- /* no longer in EQ subview mode */
- return;
- }
-
- boost::shared_ptr<AutomationControl> control = pc.lock ();
- if (control) {
- float val = control->get_value();
- do_parameter_display (control->desc(), val, true);
- /* update pot/encoder */
- _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
- }
-}
-
-void
-Strip::notify_dyn_change (boost::weak_ptr<AutomationControl> pc, bool force_update, bool propagate_mode)
-{
- boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
-
- if (!r) {
- /* not in subview mode */
- return;
- }
-
- if (_surface->mcp().subview_mode() != MackieControlProtocol::Dynamics) {
- /* no longer in EQ subview mode */
- return;
- }
-
- boost::shared_ptr<AutomationControl> control= pc.lock ();
- bool reset_all = false;
-
- if (propagate_mode && reset_all) {
- _surface->subview_mode_changed ();
- }
-
- if (control) {
- float val = control->get_value();
- if (control == r->comp_mode_controllable ()) {
- pending_display[1] = r->comp_mode_name (val);
- } else {
- do_parameter_display (control->desc(), val, true);
- }
- /* update pot/encoder */
- _surface->write (_vpot->set (control->internal_to_interface (val), true, Pot::wrap));
- }
-}
-
-void
Strip::notify_panner_azi_changed (bool force_update)
{
if (!_stripable) {
@@ -659,85 +512,13 @@ Strip::select_event (Button&, ButtonState bs)
void
Strip::vselect_event (Button&, ButtonState bs)
{
- if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
-
+ if (_surface->mcp().subview()->subview_mode() != SubViewMode::None) {
/* most subview modes: vpot press acts like a button for toggle parameters */
-
if (bs != press) {
return;
}
-
- if (_surface->mcp().subview_mode() != MackieControlProtocol::Sends) {
-
- boost::shared_ptr<AutomationControl> control = _vpot->control ();
- if (!control) {
- return;
- }
-
- Controllable::GroupControlDisposition gcd;
- if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
- gcd = Controllable::InverseGroup;
- } else {
- gcd = Controllable::UseGroup;
- }
-
- if (control->toggled()) {
- if (control->toggled()) {
- control->set_value (!control->get_value(), gcd);
- }
-
- } else if (control->desc().enumeration || control->desc().integer_step) {
-
- double val = control->get_value ();
- if (val <= control->upper() - 1.0) {
- control->set_value (val + 1.0, gcd);
- } else {
- control->set_value (control->lower(), gcd);
- }
- }
-
- } else {
-
- /* Send mode: press enables/disables the relevant
- * send, but the vpot is bound to the send-level so we
- * need to lookup the enable/disable control
- * explicitly.
- */
-
- boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
-
- if (r) {
-
- const uint32_t global_pos = _surface->mcp().global_index (*this);
- boost::shared_ptr<AutomationControl> control = r->send_enable_controllable (global_pos);
-
- if (control) {
- bool currently_enabled = (bool) control->get_value();
- Controllable::GroupControlDisposition gcd;
-
- if (_surface->mcp().main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
- gcd = Controllable::InverseGroup;
- } else {
- gcd = Controllable::UseGroup;
- }
-
- control->set_value (!currently_enabled, gcd);
-
- if (currently_enabled) {
- /* we just turned it off */
- pending_display[1] = "off";
- } else {
- /* we just turned it on, show the level
- */
- control = _stripable->send_level_controllable (global_pos);
- do_parameter_display (control->desc(), control->get_value()); // BusSendLevel
- }
- }
- }
- }
-
- /* done with this event in subview mode */
-
+
+ _surface->mcp().subview()->handle_vselect_event(_surface->mcp().global_index (*this));
return;
}
@@ -877,9 +658,14 @@ Strip::handle_button (Button& button, ButtonState bs)
}
}
-void
-Strip::do_parameter_display (ARDOUR::ParameterDescriptor const& desc, float val, bool screen_hold)
+std::string
+Strip::format_paramater_for_display(
+ ARDOUR::ParameterDescriptor const& desc,
+ float val,
+ boost::shared_ptr<ARDOUR::Stripable> stripable_for_non_mixbus_azimuth_automation,
+ bool& overwrite_screen_hold)
{
+ std::string formatted_parameter_display;
char buf[16];
switch (desc.type) {
@@ -888,12 +674,12 @@ Strip::do_parameter_display (ARDOUR::ParameterDescriptor const& desc, float val,
case TrimAutomation:
// we can't use value_as_string() that'll suffix "dB" and also use "-inf" w/o space :(
if (val == 0.0) {
- pending_display[1] = " -inf ";
+ formatted_parameter_display = " -inf ";
} else {
float dB = accurate_coefficient_to_dB (val);
snprintf (buf, sizeof (buf), "%6.1f", dB);
- pending_display[1] = buf;
- screen_hold = true;
+ formatted_parameter_display = buf;
+ overwrite_screen_hold = true;
}
break;
@@ -901,26 +687,34 @@ Strip::do_parameter_display (ARDOUR::ParameterDescriptor const& desc, float val,
if (Profile->get_mixbus()) {
// XXX no _stripable check?
snprintf (buf, sizeof (buf), "%2.1f", val);
- pending_display[1] = buf;
- screen_hold = true;
+ formatted_parameter_display = buf;
+ overwrite_screen_hold = true;
} else {
- if (_stripable) {
- boost::shared_ptr<AutomationControl> pa = _stripable->pan_azimuth_control();
+ if (stripable_for_non_mixbus_azimuth_automation) {
+ boost::shared_ptr<AutomationControl> pa = stripable_for_non_mixbus_azimuth_automation->pan_azimuth_control();
if (pa) {
- pending_display[1] = pa->get_user_string ();
- screen_hold = true;
+ formatted_parameter_display = pa->get_user_string ();
+ overwrite_screen_hold = true;
}
}
}
break;
default:
- pending_display[1] = ARDOUR::value_as_string (desc, val);
- if (pending_display[1].size () < 6) { // left-padding, right-align
- pending_display[1].insert (0, 6 - pending_display[1].size (), ' ');
+ formatted_parameter_display = ARDOUR::value_as_string (desc, val);
+ if (formatted_parameter_display.size () < 6) { // left-padding, right-align
+ formatted_parameter_display.insert (0, 6 - formatted_parameter_display.size (), ' ');
}
break;
}
+
+ return formatted_parameter_display;
+}
+void
+Strip::do_parameter_display (ARDOUR::ParameterDescriptor const& desc, float val, bool screen_hold)
+{
+ pending_display[1] = format_paramater_for_display(desc, val, _stripable, screen_hold);
+
if (screen_hold) {
/* we just queued up a parameter to be displayed.
1 second from now, switch back to vpot mode display.
@@ -1105,7 +899,7 @@ Strip::update_meter ()
return;
}
- if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
+ if (_surface->mcp().subview()->subview_mode() != SubViewMode::None) {
return;
}
@@ -1193,7 +987,7 @@ Strip::unlock_controls ()
string
Strip::vpot_mode_string ()
{
- if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
+ if (_surface->mcp().subview()->subview_mode() != SubViewMode::None) {
return string();
}
@@ -1230,7 +1024,7 @@ Strip::vpot_mode_string ()
void
Strip::flip_mode_changed ()
{
- if (_surface->mcp().subview_mode() == MackieControlProtocol::Sends) {
+ if (_surface->mcp().subview()->permit_flipping_faders_and_pots()) {
boost::shared_ptr<AutomationControl> pot_control = _vpot->control();
boost::shared_ptr<AutomationControl> fader_control = _fader->control();
@@ -1281,7 +1075,7 @@ Strip::return_to_vpot_mode_display ()
back the mode where it shows what the VPot controls.
*/
- if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
+ if (_surface->mcp().subview()->subview_mode() != SubViewMode::None) {
/* do nothing - second line shows value of current subview parameter */
return;
} else if (_stripable) {
@@ -1312,7 +1106,7 @@ Strip::next_pot_mode ()
}
- if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
+ if (_surface->mcp().subview()->subview_mode() != SubViewMode::None) {
return;
}
@@ -1344,12 +1138,8 @@ Strip::next_pot_mode ()
void
Strip::subview_mode_changed ()
{
- boost::shared_ptr<Stripable> r = _surface->mcp().subview_stripable();
-
- subview_connections.drop_connections ();
-
- switch (_surface->mcp().subview_mode()) {
- case MackieControlProtocol::None:
+ switch (_surface->mcp().subview()->subview_mode()) {
+ case SubViewMode::None:
set_vpot_parameter (_pan_mode);
/* need to show strip name again */
show_stripable_name ();
@@ -1358,332 +1148,16 @@ Strip::subview_mode_changed ()
_surface->write (_fader->set_position (0.0));
}
notify_metering_state_changed ();
- eq_band = -1;
- break;
-
- case MackieControlProtocol::EQ:
- if (r) {
- setup_eq_vpot (r);
- } else {
- /* leave it as it was */
- }
- break;
-
- case MackieControlProtocol::Dynamics:
- if (r) {
- setup_dyn_vpot (r);
- } else {
- /* leave it as it was */
- }
- eq_band = -1;
break;
- case MackieControlProtocol::Sends:
- if (r) {
- setup_sends_vpot (r);
- } else {
- /* leave it as it was */
- }
- eq_band = -1;
+ case SubViewMode::EQ:
+ case SubViewMode::Dynamics:
+ case SubViewMode::Sends:
+ case SubViewMode::TrackView:
+ case SubViewMode::Plugin:
+ _surface->mcp().subview()->setup_vpot(this, _vpot, pending_display);
break;
- case MackieControlProtocol::TrackView:
- if (r) {
- setup_trackview_vpot (r);
- } else {
- /* leave it as it was */
- }
- eq_band = -1;
- break;
- }
-}
-
-void
-Strip::setup_dyn_vpot (boost::shared_ptr<Stripable> r)
-{
- if (!r) {
- return;
- }
-
- boost::shared_ptr<AutomationControl> tc = r->comp_threshold_controllable ();
- boost::shared_ptr<AutomationControl> sc = r->comp_speed_controllable ();
- boost::shared_ptr<AutomationControl> mc = r->comp_mode_controllable ();
- boost::shared_ptr<AutomationControl> kc = r->comp_makeup_controllable ();
- boost::shared_ptr<AutomationControl> ec = r->comp_enable_controllable ();
-
-#ifdef MIXBUS32C //Mixbus32C needs to spill the filter controls into the comp section
- boost::shared_ptr<AutomationControl> hpfc = r->filter_freq_controllable (true);
- boost::shared_ptr<AutomationControl> lpfc = r->filter_freq_controllable (false);
- boost::shared_ptr<AutomationControl> fec = r->filter_enable_controllable (true); // shared HP/LP
-#endif
-
- uint32_t pos = _surface->mcp().global_index (*this);
-
- /* we will control the pos-th available parameter, from the list in the
- * order shown above.
- */
-
- vector<std::pair<boost::shared_ptr<AutomationControl>, std::string > > available;
- vector<AutomationType> params;
-
- if (tc) { available.push_back (std::make_pair (tc, "Thresh")); }
- if (sc) { available.push_back (std::make_pair (sc, mc ? r->comp_speed_name (mc->get_value()) : "Speed")); }
- if (mc) { available.push_back (std::make_pair (mc, "Mode")); }
- if (kc) { available.push_back (std::make_pair (kc, "Makeup")); }
- if (ec) { available.push_back (std::make_pair (ec, "on/off")); }
-
-#ifdef MIXBUS32C //Mixbus32C needs to spill the filter controls into the comp section
- if (hpfc) { available.push_back (std::make_pair (hpfc, "HPF")); }
- if (lpfc) { available.push_back (std::make_pair (lpfc, "LPF")); }
- if (fec) { available.push_back (std::make_pair (fec, "FiltIn")); }
-#endif
-
- if (pos >= available.size()) {
- /* this knob is not needed to control the available parameters */
- _vpot->set_control (boost::shared_ptr<AutomationControl>());
- pending_display[0] = string();
- pending_display[1] = string();
- return;
- }
-
- boost::shared_ptr<AutomationControl> pc;
-
- pc = available[pos].first;
- string pot_id = available[pos].second;
-
- pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_dyn_change, this, boost::weak_ptr<AutomationControl>(pc), false, true), ui_context());
- _vpot->set_control (pc);
-
- if (!pot_id.empty()) {
- pending_display[0] = pot_id;
- } else {
- pending_display[0] = string();
}
-
- notify_dyn_change (boost::weak_ptr<AutomationControl>(pc), true, false);
-}
-
-void
-Strip::setup_eq_vpot (boost::shared_ptr<Stripable> r)
-{
- boost::shared_ptr<AutomationControl> pc;
- string pot_id;
-
-#ifdef MIXBUS
- const uint32_t global_pos = _surface->mcp().global_index (*this);
- int eq_band = -1;
- std::string band_name;
- if (r->is_input_strip ()) {
-
-#ifdef MIXBUS32C
- switch (global_pos) {
- case 0:
- case 2:
- case 4:
- case 6:
- eq_band = global_pos / 2;
- pc = r->eq_freq_controllable (eq_band);
- band_name = r->eq_band_name (eq_band);
- pot_id = band_name + "Freq";
- break;
- case 1:
- case 3:
- case 5:
- case 7:
- eq_band = global_pos / 2;
- pc = r->eq_gain_controllable (eq_band);
- band_name = r->eq_band_name (eq_band);
- pot_id = band_name + "Gain";
- break;
- case 8:
- pc = r->eq_shape_controllable(0); //low band "bell" button
- band_name = "lo";
- pot_id = band_name + " Shp";
- break;
- case 9:
- pc = r->eq_shape_controllable(3); //high band "bell" button
- band_name = "hi";
- pot_id = band_name + " Shp";
- break;
- case 10:
- pc = r->eq_enable_controllable();
- pot_id = "EQ";
- break;
- }
-
-#else //regular Mixbus channel EQ
-
- switch (global_pos) {
- case 0:
- case 2:
- case 4:
- eq_band = global_pos / 2;
- pc = r->eq_gain_controllable (eq_band);
- band_name = r->eq_band_name (eq_band);
- pot_id = band_name + "Gain";
- break;
- case 1:
- case 3:
- case 5:
- eq_band = global_pos / 2;
- pc = r->eq_freq_controllable (eq_band);
- band_name = r->eq_band_name (eq_band);
- pot_id = band_name + "Freq";
- break;
- case 6:
- pc = r->eq_enable_controllable();
- pot_id = "EQ";
- break;
- case 7:
- pc = r->filter_freq_controllable(true);
- pot_id = "HP Freq";
- break;
- }
-
-#endif
-
- } else { //mixbus or master bus ( these are currently the same for MB & 32C )
- switch (global_pos) {
- case 0:
- case 1:
- case 2:
- eq_band = global_pos;
- pc = r->eq_gain_controllable (eq_band);
- band_name = r->eq_band_name (eq_band);
- pot_id = band_name + "Gain";
- break;
- }
- }
-#endif
-
- //If a controllable was found, connect it up, and put the labels in the display.
- if (pc) {
- pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_eq_change, this, boost::weak_ptr<AutomationControl>(pc), false), ui_context());
- _vpot->set_control (pc);
-
- if (!pot_id.empty()) {
- pending_display[0] = pot_id;
- } else {
- pending_display[0] = string();
- }
-
- } else { //no controllable was found; just clear this knob
- _vpot->set_control (boost::shared_ptr<AutomationControl>());
- pending_display[0] = string();
- pending_display[1] = string();
- }
-
- notify_eq_change (boost::weak_ptr<AutomationControl>(pc), true);
-}
-
-void
-Strip::setup_sends_vpot (boost::shared_ptr<Stripable> r)
-{
- if (!r) {
- return;
- }
-
- const uint32_t global_pos = _surface->mcp().global_index (*this);
-
- boost::shared_ptr<AutomationControl> pc = r->send_level_controllable (global_pos);
-
- if (!pc) {
- /* nothing to control */
- _vpot->set_control (boost::shared_ptr<AutomationControl>());
- pending_display[0] = string();
- pending_display[1] = string();
- return;
- }
-
- pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_send_level_change, this, global_pos, false), ui_context());
- _vpot->set_control (pc);
-
- pending_display[0] = PBD::short_version (r->send_name (global_pos), 6);
-
- notify_send_level_change (global_pos, true);
-}
-
-void
-Strip::setup_trackview_vpot (boost::shared_ptr<Stripable> r)
-{
- if (!r) {
- return;
- }
-
- const uint32_t global_pos = _surface->mcp().global_index (*this);
-
- if (global_pos >= 8) {
- /* nothing to control */
- _vpot->set_control (boost::shared_ptr<AutomationControl>());
- pending_display[0] = string();
- pending_display[1] = string();
- return;
- }
-
- boost::shared_ptr<AutomationControl> pc;
- boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (r);
- string label;
-
- switch (global_pos) {
- case 0:
- pc = r->trim_control ();
- if (pc) {
- pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, TrimAutomation, global_pos, false), ui_context());
- pending_display[0] = "Trim";
- notify_trackview_change (TrimAutomation, global_pos, true);
- }
- break;
- case 1:
- if (track) {
- pc = track->monitoring_control();
- if (pc) {
- pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, MonitoringAutomation, global_pos, false), ui_context());
- pending_display[0] = "Mon";
- notify_trackview_change (MonitoringAutomation, global_pos, true);
- }
- }
- break;
- case 2:
- pc = r->solo_isolate_control ();
- if (pc) {
- pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloIsolateAutomation, global_pos, false), ui_context());
- notify_trackview_change (SoloIsolateAutomation, global_pos, true);
- pending_display[0] = "S-Iso";
- }
- break;
- case 3:
- pc = r->solo_safe_control ();
- if (pc) {
- pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, SoloSafeAutomation, global_pos, false), ui_context());
- notify_trackview_change (SoloSafeAutomation, global_pos, true);
- pending_display[0] = "S-Safe";
- }
- break;
- case 4:
- pc = r->phase_control();
- if (pc) {
- pc->Changed.connect (subview_connections, MISSING_INVALIDATOR, boost::bind (&Strip::notify_trackview_change, this, PhaseAutomation, global_pos, false), ui_context());
- notify_trackview_change (PhaseAutomation, global_pos, true);
- pending_display[0] = "Phase";
- }
- break;
- case 5:
- // pc = r->trim_control ();
- break;
- case 6:
- // pc = r->trim_control ();
- break;
- case 7:
- // pc = r->trim_control ();
- break;
- }
-
- if (!pc) {
- pending_display[0] = string();
- pending_display[1] = string();
- return;
- }
-
- _vpot->set_control (pc);
}
void
@@ -1745,7 +1219,7 @@ Strip::reset_saved_values ()
void
Strip::notify_metering_state_changed()
{
- if (_surface->mcp().subview_mode() != MackieControlProtocol::None) {
+ if (_surface->mcp().subview()->subview_mode() != SubViewMode::None) {
return;
}
diff --git a/libs/surfaces/mackie/strip.h b/libs/surfaces/mackie/strip.h
index e1dc344b6c..377999ba0f 100644
--- a/libs/surfaces/mackie/strip.h
+++ b/libs/surfaces/mackie/strip.h
@@ -93,6 +93,12 @@ public:
MidiByteArray display (uint32_t line_number, const std::string&);
MidiByteArray blank_display (uint32_t line_number);
+
+ static std::string format_paramater_for_display(
+ ARDOUR::ParameterDescriptor const& desc,
+ float val,
+ boost::shared_ptr<ARDOUR::Stripable> stripable_for_non_mixbus_azimuth_automation,
+ bool& overwrite_screen_hold);
void zero ();
@@ -136,9 +142,6 @@ private:
uint64_t return_to_vpot_mode_display_at;
boost::shared_ptr<ARDOUR::Stripable> _stripable;
PBD::ScopedConnectionList stripable_connections;
- PBD::ScopedConnectionList subview_connections;
- PBD::ScopedConnectionList send_connections;
- int eq_band;
ARDOUR::AutomationType _pan_mode;
@@ -178,18 +181,6 @@ private:
void reset_saved_values ();
bool is_midi_track () const;
-
- void notify_eq_change (boost::weak_ptr<ARDOUR::AutomationControl>, bool force);
- void setup_eq_vpot (boost::shared_ptr<ARDOUR::Stripable>);
-
- void notify_dyn_change (boost::weak_ptr<ARDOUR::AutomationControl>, bool force, bool propagate_mode_change);
- void setup_dyn_vpot (boost::shared_ptr<ARDOUR::Stripable>);
-
- void notify_send_level_change (uint32_t band, bool force);
- void setup_sends_vpot (boost::shared_ptr<ARDOUR::Stripable>);
-
- void notify_trackview_change (ARDOUR::AutomationType, uint32_t band, bool force);
- void setup_trackview_vpot (boost::shared_ptr<ARDOUR::Stripable>);
};
}
diff --git a/libs/surfaces/mackie/subview.cc b/libs/surfaces/mackie/subview.cc
new file mode 100644
index 0000000000..8961fdac65
--- /dev/null
+++ b/libs/surfaces/mackie/subview.cc
@@ -0,0 +1,1233 @@
+/*
+ * Copyright (C) 2006-2007 John Anderson
+ * Copyright (C) 2007-2010 David Robillard <d@drobilla.net>
+ * Copyright (C) 2007-2017 Paul Davis <paul@linuxaudiosystems.com>
+ * Copyright (C) 2009-2012 Carl Hetherington <carl@carlh.net>
+ * Copyright (C) 2015-2016 Len Ovens <len@ovenwerks.net>
+ * Copyright (C) 2015-2019 Robin Gareus <robin@gareus.org>
+ * Copyright (C) 2016-2018 Ben Loftis <ben@harrisonconsoles.com>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include "pbd/convert.h"
+#include "pbd/failed_constructor.h"
+
+#include "ardour/debug.h"
+#include "ardour/monitor_control.h"
+#include "ardour/phase_control.h"
+#include "ardour/plugin.h"
+#include "ardour/plugin_insert.h"
+#include "ardour/route.h"
+#include "ardour/solo_isolate_control.h"
+#include "ardour/stripable.h"
+#include "ardour/track.h"
+
+#include "mackie_control_protocol.h"
+#include "pot.h"
+#include "strip.h"
+#include "subview.h"
+#include "surface.h"
+
+using namespace ARDOUR;
+using namespace ArdourSurface;
+using namespace Mackie;
+using namespace PBD;
+
+#define ui_context() MackieControlProtocol::instance() /* a UICallback-derived object that specifies the event loop for signal handling */
+
+SubviewFactory* SubviewFactory::_instance = 0;
+
+SubviewFactory* SubviewFactory::instance() {
+ if (!_instance) {
+ _instance = new SubviewFactory();
+ }
+ return _instance;
+}
+
+SubviewFactory::SubviewFactory() {};
+
+boost::shared_ptr<Subview> SubviewFactory::create_subview(
+ SubViewMode svm,
+ MackieControlProtocol& mcp,
+ boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+{
+ switch (svm) {
+ case SubViewMode::EQ:
+ return boost::make_shared<EQSubview>(mcp, subview_stripable);
+ case SubViewMode::Dynamics:
+ return boost::make_shared<DynamicsSubview>(mcp, subview_stripable);
+ case SubViewMode::Sends:
+ return boost::make_shared<SendsSubview>(mcp, subview_stripable);
+ case SubViewMode::TrackView:
+ return boost::make_shared<TrackViewSubview>(mcp, subview_stripable);
+ case SubViewMode::Plugin:
+ return boost::make_shared<PluginSubview>(mcp, subview_stripable);
+ case SubViewMode::None:
+ default:
+ return boost::make_shared<NoneSubview>(mcp, subview_stripable);
+ }
+}
+
+
+Subview::Subview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+ : _mcp(mcp)
+ , _subview_stripable(subview_stripable)
+{
+ init_strip_vectors();
+}
+
+Subview::~Subview()
+{
+ reset_all_vpot_controls();
+}
+
+void
+Subview::reset_all_vpot_controls()
+{
+ for (std::vector<Pot*>::iterator iter = _strip_vpots_over_all_surfaces.begin(); iter != _strip_vpots_over_all_surfaces.end(); ) {
+ std::vector<Pot*>::iterator tmp;
+
+ tmp = iter;
+ ++tmp;
+
+ if (*iter != 0)
+ {
+ (*iter)->set_control (boost::shared_ptr<AutomationControl>());
+ }
+
+ iter = tmp;
+ }
+}
+
+void Subview::handle_vselect_event(uint32_t global_strip_position)
+{
+ Strip* strip = 0;
+ Pot* vpot = 0;
+ std::string* pending_display = 0;
+ if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position))
+ {
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> control = vpot->control ();
+ if (!control) {
+ return;
+ }
+
+ Controllable::GroupControlDisposition gcd;
+ if (_mcp.main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
+ gcd = Controllable::InverseGroup;
+ } else {
+ gcd = Controllable::UseGroup;
+ }
+
+ if (control->toggled()) {
+ if (control->toggled()) {
+ control->set_value (!control->get_value(), gcd);
+ }
+
+ } else if (control->desc().enumeration || control->desc().integer_step) {
+
+ double val = control->get_value ();
+ if (val <= control->upper() - 1.0) {
+ control->set_value (val + 1.0, gcd);
+ } else {
+ control->set_value (control->lower(), gcd);
+ }
+ }
+}
+
+bool
+Subview::subview_mode_would_be_ok (SubViewMode mode, boost::shared_ptr<Stripable> r, std::string& reason_why_not)
+{
+ switch (mode) {
+ case SubViewMode::None:
+ return NoneSubview::subview_mode_would_be_ok(r, reason_why_not);
+ case SubViewMode::Sends:
+ return SendsSubview::subview_mode_would_be_ok(r, reason_why_not);
+ case SubViewMode::EQ:
+ return EQSubview::subview_mode_would_be_ok(r, reason_why_not);
+ case SubViewMode::Dynamics:
+ return DynamicsSubview::subview_mode_would_be_ok(r, reason_why_not);
+ case SubViewMode::TrackView:
+ return TrackViewSubview::subview_mode_would_be_ok(r, reason_why_not);
+ case SubViewMode::Plugin:
+ return PluginSubview::subview_mode_would_be_ok(r, reason_why_not);
+ }
+
+ return false;
+}
+
+void
+Subview::notify_subview_stripable_deleted ()
+{
+ _subview_stripable.reset ();
+}
+
+void
+Subview::init_strip_vectors()
+{
+ _strips_over_all_surfaces.resize(_mcp.n_strips(), 0);
+ _strip_vpots_over_all_surfaces.resize(_mcp.n_strips(), 0);
+ _strip_pending_displays_over_all_surfaces.resize(_mcp.n_strips(), 0);
+}
+
+void
+Subview::store_pointers(Strip* strip, Pot* vpot, std::string* pending_display, uint32_t global_strip_position)
+{
+ if (global_strip_position >= _strips_over_all_surfaces.size() ||
+ global_strip_position >= _strip_vpots_over_all_surfaces.size() ||
+ global_strip_position >= _strip_pending_displays_over_all_surfaces.size())
+ {
+ return;
+ }
+
+ _strips_over_all_surfaces[global_strip_position] = strip;
+ _strip_vpots_over_all_surfaces[global_strip_position] = vpot;
+ _strip_pending_displays_over_all_surfaces[global_strip_position] = pending_display;
+}
+
+bool
+Subview::retrieve_pointers(Strip** strip, Pot** vpot, std::string** pending_display, uint32_t global_strip_position)
+{
+ if (global_strip_position >= _strips_over_all_surfaces.size() ||
+ global_strip_position >= _strip_vpots_over_all_surfaces.size() ||
+ global_strip_position >= _strip_pending_displays_over_all_surfaces.size())
+ {
+ return false;
+ }
+
+ *strip = _strips_over_all_surfaces[global_strip_position];
+ *vpot = _strip_vpots_over_all_surfaces[global_strip_position];
+ *pending_display = _strip_pending_displays_over_all_surfaces[global_strip_position];
+
+ if (!strip || !vpot || !pending_display)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+void Subview::do_parameter_display(std::string& display, const ParameterDescriptor& pd, float param_val, Strip* strip, bool screen_hold)
+{
+ display = Strip::format_paramater_for_display(
+ pd,
+ param_val,
+ strip->stripable(),
+ screen_hold
+ );
+
+ if (screen_hold) {
+ /* we just queued up a parameter to be displayed.
+ 1 second from now, switch back to vpot mode display.
+ */
+ strip->block_vpot_mode_display_for (1000);
+ }
+}
+
+
+
+NoneSubview::NoneSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+ : Subview(mcp, subview_stripable)
+{}
+
+NoneSubview::~NoneSubview()
+{}
+
+bool NoneSubview::subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not)
+{
+ // always possible
+ return true;
+}
+
+void NoneSubview::update_global_buttons()
+{
+ _mcp.update_global_button (Button::Send, off);
+ _mcp.update_global_button (Button::Plugin, off);
+ _mcp.update_global_button (Button::Eq, off);
+ _mcp.update_global_button (Button::Dyn, off);
+ _mcp.update_global_button (Button::Track, off);
+ _mcp.update_global_button (Button::Pan, on);
+}
+
+void NoneSubview::setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2])
+{
+ // nothing to be done here. All pots are set in strip.cc
+}
+
+
+
+EQSubview::EQSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+ : Subview(mcp, subview_stripable)
+{}
+
+EQSubview::~EQSubview()
+{}
+
+bool EQSubview::subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not)
+{
+ if (r && r->eq_band_cnt() > 0) {
+ return true;
+ }
+
+ reason_why_not = "no EQ in the track/bus";
+ return false;
+}
+
+void EQSubview::update_global_buttons()
+{
+ _mcp.update_global_button (Button::Send, off);
+ _mcp.update_global_button (Button::Plugin, off);
+ _mcp.update_global_button (Button::Eq, on);
+ _mcp.update_global_button (Button::Dyn, off);
+ _mcp.update_global_button (Button::Track, off);
+ _mcp.update_global_button (Button::Pan, off);
+}
+
+void EQSubview::setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2])
+{
+ const uint32_t global_strip_position = _mcp.global_index (*strip);
+ store_pointers(strip, vpot, pending_display, global_strip_position);
+
+ if (!_subview_stripable) {
+ return;
+ }
+
+
+ boost::shared_ptr<AutomationControl> pc;
+ std::string pot_id;
+
+#ifdef MIXBUS
+ int eq_band = -1;
+ std::string band_name;
+ if (_subview_stripable->is_input_strip ()) {
+
+#ifdef MIXBUS32C
+ switch (global_strip_position) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ eq_band = global_strip_position / 2;
+ pc = _subview_stripable->eq_freq_controllable (eq_band);
+ band_name = _subview_stripable->eq_band_name (eq_band);
+ pot_id = band_name + "Freq";
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ eq_band = global_strip_position / 2;
+ pc = _subview_stripable->eq_gain_controllable (eq_band);
+ band_name = _subview_stripable->eq_band_name (eq_band);
+ pot_id = band_name + "Gain";
+ break;
+ case 8:
+ pc = _subview_stripable->eq_shape_controllable(0); //low band "bell" button
+ band_name = "lo";
+ pot_id = band_name + " Shp";
+ break;
+ case 9:
+ pc = _subview_stripable->eq_shape_controllable(3); //high band "bell" button
+ band_name = "hi";
+ pot_id = band_name + " Shp";
+ break;
+ case 10:
+ pc = _subview_stripable->eq_enable_controllable();
+ pot_id = "EQ";
+ break;
+ }
+
+#else //regular Mixbus channel EQ
+
+ switch (global_strip_position) {
+ case 0:
+ case 2:
+ case 4:
+ eq_band = global_strip_position / 2;
+ pc = _subview_stripable->eq_gain_controllable (eq_band);
+ band_name = _subview_stripable->eq_band_name (eq_band);
+ pot_id = band_name + "Gain";
+ break;
+ case 1:
+ case 3:
+ case 5:
+ eq_band = global_strip_position / 2;
+ pc = _subview_stripable->eq_freq_controllable (eq_band);
+ band_name = _subview_stripable->eq_band_name (eq_band);
+ pot_id = band_name + "Freq";
+ break;
+ case 6:
+ pc = _subview_stripable->eq_enable_controllable();
+ pot_id = "EQ";
+ break;
+ case 7:
+ pc = _subview_stripable->filter_freq_controllable(true);
+ pot_id = "HP Freq";
+ break;
+ }
+
+#endif
+
+ } else { //mixbus or master bus ( these are currently the same for MB & 32C )
+ switch (global_strip_position) {
+ case 0:
+ case 1:
+ case 2:
+ eq_band = global_strip_position;
+ pc = _subview_stripable->eq_gain_controllable (eq_band);
+ band_name = _subview_stripable->eq_band_name (eq_band);
+ pot_id = band_name + "Gain";
+ break;
+ }
+ }
+#endif
+
+ //If a controllable was found, connect it up, and put the labels in the display.
+ if (pc) {
+ pc->Changed.connect (_subview_connections, MISSING_INVALIDATOR, boost::bind (&EQSubview::notify_change, this, boost::weak_ptr<AutomationControl>(pc), global_strip_position, false), ui_context());
+ vpot->set_control (pc);
+
+ if (!pot_id.empty()) {
+ pending_display[0] = pot_id;
+ } else {
+ pending_display[0] = std::string();
+ }
+
+ } else { //no controllable was found; just clear this knob
+ vpot->set_control (boost::shared_ptr<AutomationControl>());
+ pending_display[0] = std::string();
+ pending_display[1] = std::string();
+ }
+
+ notify_change (boost::weak_ptr<AutomationControl>(pc), global_strip_position, true);
+}
+
+void EQSubview::notify_change (boost::weak_ptr<ARDOUR::AutomationControl> pc, uint32_t global_strip_position, bool force)
+{
+ if (!_subview_stripable) {
+ return;
+ }
+
+ Strip* strip = 0;
+ Pot* vpot = 0;
+ std::string* pending_display = 0;
+ if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position))
+ {
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> control = pc.lock ();
+ if (control) {
+ float val = control->get_value();
+ do_parameter_display(pending_display[1], control->desc(), val, strip, true);
+ /* update pot/encoder */
+ strip->surface()->write (vpot->set (control->internal_to_interface (val), true, Pot::wrap));
+ }
+}
+
+
+
+DynamicsSubview::DynamicsSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+ : Subview(mcp, subview_stripable)
+{}
+
+DynamicsSubview::~DynamicsSubview()
+{}
+
+bool DynamicsSubview::subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not)
+{
+ if (r && r->comp_enable_controllable()) {
+ return true;
+ }
+
+ reason_why_not = "no dynamics in selected track/bus";
+ return false;
+}
+
+void DynamicsSubview::update_global_buttons()
+{
+ _mcp.update_global_button (Button::Send, off);
+ _mcp.update_global_button (Button::Plugin, off);
+ _mcp.update_global_button (Button::Eq, off);
+ _mcp.update_global_button (Button::Dyn, on);
+ _mcp.update_global_button (Button::Track, off);
+ _mcp.update_global_button (Button::Pan, off);
+}
+
+void DynamicsSubview::setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2])
+{
+ const uint32_t global_strip_position = _mcp.global_index (*strip);
+ store_pointers(strip, vpot, pending_display, global_strip_position);
+
+ if (!_subview_stripable) {
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> tc = _subview_stripable->comp_threshold_controllable ();
+ boost::shared_ptr<AutomationControl> sc = _subview_stripable->comp_speed_controllable ();
+ boost::shared_ptr<AutomationControl> mc = _subview_stripable->comp_mode_controllable ();
+ boost::shared_ptr<AutomationControl> kc = _subview_stripable->comp_makeup_controllable ();
+ boost::shared_ptr<AutomationControl> ec = _subview_stripable->comp_enable_controllable ();
+
+#ifdef MIXBUS32C //Mixbus32C needs to spill the filter controls into the comp section
+ boost::shared_ptr<AutomationControl> hpfc = _subview_stripable->filter_freq_controllable (true);
+ boost::shared_ptr<AutomationControl> lpfc = _subview_stripable->filter_freq_controllable (false);
+ boost::shared_ptr<AutomationControl> fec = _subview_stripable->filter_enable_controllable (true); // shared HP/LP
+#endif
+
+ /* we will control the global_strip_position-th available parameter, from the list in the
+ * order shown above.
+ */
+
+ std::vector<std::pair<boost::shared_ptr<AutomationControl>, std::string > > available;
+ std::vector<AutomationType> params;
+
+ if (tc) { available.push_back (std::make_pair (tc, "Thresh")); }
+ if (sc) { available.push_back (std::make_pair (sc, mc ? _subview_stripable->comp_speed_name (mc->get_value()) : "Speed")); }
+ if (mc) { available.push_back (std::make_pair (mc, "Mode")); }
+ if (kc) { available.push_back (std::make_pair (kc, "Makeup")); }
+ if (ec) { available.push_back (std::make_pair (ec, "on/off")); }
+
+#ifdef MIXBUS32C //Mixbus32C needs to spill the filter controls into the comp section
+ if (hpfc) { available.push_back (std::make_pair (hpfc, "HPF")); }
+ if (lpfc) { available.push_back (std::make_pair (lpfc, "LPF")); }
+ if (fec) { available.push_back (std::make_pair (fec, "FiltIn")); }
+#endif
+
+ if (global_strip_position >= available.size()) {
+ /* this knob is not needed to control the available parameters */
+ vpot->set_control (boost::shared_ptr<AutomationControl>());
+ pending_display[0] = std::string();
+ pending_display[1] = std::string();
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> pc;
+
+ pc = available[global_strip_position].first;
+ std::string pot_id = available[global_strip_position].second;
+
+ pc->Changed.connect (_subview_connections, MISSING_INVALIDATOR, boost::bind (&DynamicsSubview::notify_change, this, boost::weak_ptr<AutomationControl>(pc), global_strip_position, false, true), ui_context());
+ vpot->set_control (pc);
+
+ if (!pot_id.empty()) {
+ pending_display[0] = pot_id;
+ } else {
+ pending_display[0] = std::string();
+ }
+
+ notify_change (boost::weak_ptr<AutomationControl>(pc), global_strip_position, true, false);
+}
+
+void
+DynamicsSubview::notify_change (boost::weak_ptr<ARDOUR::AutomationControl> pc, uint32_t global_strip_position, bool force, bool propagate_mode)
+{
+ if (!_subview_stripable)
+ {
+ return;
+ }
+
+ Strip* strip = 0;
+ Pot* vpot = 0;
+ std::string* pending_display = 0;
+ if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position))
+ {
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> control= pc.lock ();
+ bool reset_all = false;
+
+ if (propagate_mode && reset_all) {
+ // @TODO: this line can never be reached due to reset_all being set to false. What was intended here?
+ strip->surface()->subview_mode_changed ();
+ }
+
+ if (control) {
+ float val = control->get_value();
+ if (control == _subview_stripable->comp_mode_controllable ()) {
+ pending_display[1] = _subview_stripable->comp_mode_name (val);
+ } else {
+ do_parameter_display(pending_display[1], control->desc(), val, strip, true);
+ }
+ /* update pot/encoder */
+ strip->surface()->write (vpot->set (control->internal_to_interface (val), true, Pot::wrap));
+ }
+}
+
+
+
+SendsSubview::SendsSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+ : Subview(mcp, subview_stripable)
+{}
+
+SendsSubview::~SendsSubview()
+{}
+
+bool SendsSubview::subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not)
+{
+ if (r && r->send_level_controllable (0)) {
+ return true;
+ }
+
+ reason_why_not = "no sends for selected track/bus";
+ return false;
+}
+
+void SendsSubview::update_global_buttons()
+{
+ _mcp.update_global_button (Button::Send, on);
+ _mcp.update_global_button (Button::Plugin, off);
+ _mcp.update_global_button (Button::Eq, off);
+ _mcp.update_global_button (Button::Dyn, off);
+ _mcp.update_global_button (Button::Track, off);
+ _mcp.update_global_button (Button::Pan, off);
+}
+
+void SendsSubview::setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2])
+{
+ const uint32_t global_strip_position = _mcp.global_index (*strip);
+ store_pointers(strip, vpot, pending_display, global_strip_position);
+
+ if (!_subview_stripable) {
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> pc = _subview_stripable->send_level_controllable (global_strip_position);
+
+ if (!pc) {
+ /* nothing to control */
+ vpot->set_control (boost::shared_ptr<AutomationControl>());
+ pending_display[0] = std::string();
+ pending_display[1] = std::string();
+ return;
+ }
+
+ pc->Changed.connect (_subview_connections, MISSING_INVALIDATOR, boost::bind (&SendsSubview::notify_send_level_change, this, global_strip_position, false), ui_context());
+ vpot->set_control (pc);
+
+ pending_display[0] = PBD::short_version (_subview_stripable->send_name (global_strip_position), 6);
+
+ notify_send_level_change (global_strip_position, true);
+}
+
+void
+SendsSubview::notify_send_level_change (uint32_t global_strip_position, bool force)
+{
+ if (!_subview_stripable) {
+ return;
+ }
+
+ Strip* strip = 0;
+ Pot* vpot = 0;
+ std::string* pending_display = 0;
+ if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position))
+ {
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> control = _subview_stripable->send_level_controllable (global_strip_position);
+ if (!control) {
+ return;
+ }
+
+ if (control) {
+ float val = control->get_value();
+ do_parameter_display(pending_display[1], control->desc(), val, strip, false);
+
+ if (vpot->control() == control) {
+ /* update pot/encoder */
+ strip->surface()->write (vpot->set (control->internal_to_interface (val), true, Pot::wrap));
+ }
+ }
+}
+
+void SendsSubview::handle_vselect_event(uint32_t global_strip_position)
+{
+ /* Send mode: press enables/disables the relevant
+ * send, but the vpot is bound to the send-level so we
+ * need to lookup the enable/disable control
+ * explicitly.
+ */
+
+ if (!_subview_stripable)
+ {
+ return;
+ }
+
+ Strip* strip = 0;
+ Pot* vpot = 0;
+ std::string* pending_display = 0;
+ if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position))
+ {
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> control = _subview_stripable->send_enable_controllable(global_strip_position);
+
+ if (control) {
+ bool currently_enabled = (bool) control->get_value();
+ Controllable::GroupControlDisposition gcd;
+
+ if (_mcp.main_modifier_state() & MackieControlProtocol::MODIFIER_SHIFT) {
+ gcd = Controllable::InverseGroup;
+ } else {
+ gcd = Controllable::UseGroup;
+ }
+
+ control->set_value (!currently_enabled, gcd);
+
+ if (currently_enabled) {
+ /* we just turned it off */
+ pending_display[1] = "off";
+ } else {
+ /* we just turned it on, show the level
+ */
+ control = _subview_stripable->send_level_controllable (global_strip_position);
+ do_parameter_display(pending_display[1], control->desc(), control->get_value(), strip, false);
+ }
+ }
+}
+
+
+
+TrackViewSubview::TrackViewSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+ : Subview(mcp, subview_stripable)
+{}
+
+TrackViewSubview::~TrackViewSubview()
+{}
+
+bool TrackViewSubview::subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not)
+{
+ if (r) {
+ return true;
+ }
+
+ reason_why_not = "no track view possible";
+ return false;
+}
+
+void TrackViewSubview::update_global_buttons()
+{
+ _mcp.update_global_button (Button::Send, off);
+ _mcp.update_global_button (Button::Plugin, off);
+ _mcp.update_global_button (Button::Eq, off);
+ _mcp.update_global_button (Button::Dyn, off);
+ _mcp.update_global_button (Button::Track, on);
+ _mcp.update_global_button (Button::Pan, off);
+}
+
+void TrackViewSubview::setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2])
+{
+ const uint32_t global_strip_position = _mcp.global_index (*strip);
+ store_pointers(strip, vpot, pending_display, global_strip_position);
+
+ if (global_strip_position > 4) {
+ /* nothing to control */
+ vpot->set_control (boost::shared_ptr<AutomationControl>());
+ pending_display[0] = std::string();
+ pending_display[1] = std::string();
+ return;
+ }
+
+ if (!_subview_stripable) {
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> pc;
+ boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (_subview_stripable);
+
+ switch (global_strip_position) {
+ case 0:
+ pc = _subview_stripable->trim_control ();
+ if (pc) {
+ pc->Changed.connect (_subview_connections, MISSING_INVALIDATOR, boost::bind (&TrackViewSubview::notify_change, this, TrimAutomation, global_strip_position, false), ui_context());
+ pending_display[0] = "Trim";
+ notify_change (TrimAutomation, global_strip_position, true);
+ }
+ break;
+ case 1:
+ if (track) {
+ pc = track->monitoring_control();
+ if (pc) {
+ pc->Changed.connect (_subview_connections, MISSING_INVALIDATOR, boost::bind (&TrackViewSubview::notify_change, this, MonitoringAutomation, global_strip_position, false), ui_context());
+ pending_display[0] = "Mon";
+ notify_change (MonitoringAutomation, global_strip_position, true);
+ }
+ }
+ break;
+ case 2:
+ pc = _subview_stripable->solo_isolate_control ();
+ if (pc) {
+ pc->Changed.connect (_subview_connections, MISSING_INVALIDATOR, boost::bind (&TrackViewSubview::notify_change, this, SoloIsolateAutomation, global_strip_position, false), ui_context());
+ notify_change (SoloIsolateAutomation, global_strip_position, true);
+ pending_display[0] = "S-Iso";
+ }
+ break;
+ case 3:
+ pc = _subview_stripable->solo_safe_control ();
+ if (pc) {
+ pc->Changed.connect (_subview_connections, MISSING_INVALIDATOR, boost::bind (&TrackViewSubview::notify_change, this, SoloSafeAutomation, global_strip_position, false), ui_context());
+ notify_change (SoloSafeAutomation, global_strip_position, true);
+ pending_display[0] = "S-Safe";
+ }
+ break;
+ case 4:
+ pc = _subview_stripable->phase_control();
+ if (pc) {
+ pc->Changed.connect (_subview_connections, MISSING_INVALIDATOR, boost::bind (&TrackViewSubview::notify_change, this, PhaseAutomation, global_strip_position, false), ui_context());
+ notify_change (PhaseAutomation, global_strip_position, true);
+ pending_display[0] = "Phase";
+ }
+ break;
+ }
+
+ if (!pc) {
+ pending_display[0] = std::string();
+ pending_display[1] = std::string();
+ return;
+ }
+
+ vpot->set_control (pc);
+}
+
+void
+TrackViewSubview::notify_change (AutomationType type, uint32_t global_strip_position, bool force_update)
+{
+ if (!_subview_stripable) {
+ return;
+ }
+
+ Strip* strip = 0;
+ Pot* vpot = 0;
+ std::string* pending_display = 0;
+ if (!retrieve_pointers(&strip, &vpot, &pending_display, global_strip_position))
+ {
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> control;
+ boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (_subview_stripable);
+ bool screen_hold = false;
+
+ switch (type) {
+ case TrimAutomation:
+ control = _subview_stripable->trim_control();
+ screen_hold = true;
+ break;
+ case SoloIsolateAutomation:
+ control = _subview_stripable->solo_isolate_control ();
+ break;
+ case SoloSafeAutomation:
+ control = _subview_stripable->solo_safe_control ();
+ break;
+ case MonitoringAutomation:
+ if (track) {
+ control = track->monitoring_control();
+ screen_hold = true;
+ }
+ break;
+ case PhaseAutomation:
+ control = _subview_stripable->phase_control ();
+ screen_hold = true;
+ break;
+ default:
+ break;
+ }
+
+ if (control) {
+ float val = control->get_value();
+ do_parameter_display(pending_display[1], control->desc(), val, strip, screen_hold);
+
+ /* update pot/encoder */
+ strip->surface()->write (vpot->set (control->internal_to_interface (val), true, Pot::wrap));
+ }
+}
+
+
+
+PluginSubview::PluginSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+ : Subview(mcp, subview_stripable)
+{
+ _plugin_subview_state = boost::make_shared<PluginSelect>(*this);
+ connect_processors_changed_signal();
+}
+
+PluginSubview::~PluginSubview()
+{}
+
+void PluginSubview::connect_processors_changed_signal()
+{
+ boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (_subview_stripable);
+ if (route)
+ {
+ route->processors_changed.connect(_subview_connections, MISSING_INVALIDATOR, boost::bind (&PluginSubview::handle_processors_changed, this), ui_context());
+ }
+}
+
+void PluginSubview::handle_processors_changed()
+{
+ _mcp.redisplay_subview_mode();
+}
+
+bool PluginSubview::subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not)
+{
+ if (r) {
+ boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (r);
+ if (route && route->nth_plugin(0)) {
+ return true;
+ }
+ }
+
+ reason_why_not = "no plugins in selected track/bus";
+ return false;
+}
+
+void PluginSubview::update_global_buttons()
+{
+ _mcp.update_global_button (Button::Send, off);
+ _mcp.update_global_button (Button::Plugin, on);
+ _mcp.update_global_button (Button::Eq, off);
+ _mcp.update_global_button (Button::Dyn, off);
+ _mcp.update_global_button (Button::Track, off);
+ _mcp.update_global_button (Button::Pan, off);
+}
+
+bool PluginSubview::permit_flipping_faders_and_pots()
+{
+ return _plugin_subview_state->permit_flipping_faders_and_pots();
+}
+
+void PluginSubview::setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2])
+{
+ const uint32_t global_strip_position = _mcp.global_index (*strip);
+ store_pointers(strip, vpot, pending_display, global_strip_position);
+ _plugin_subview_state->setup_vpot(strip, vpot, pending_display, global_strip_position, _subview_stripable);
+}
+
+void PluginSubview::handle_vselect_event(uint32_t global_strip_position)
+{
+ _plugin_subview_state->handle_vselect_event(global_strip_position, _subview_stripable);
+}
+
+bool PluginSubview::handle_cursor_right_press()
+{
+ return _plugin_subview_state->handle_cursor_right_press();
+}
+
+bool PluginSubview::handle_cursor_left_press()
+{
+ return _plugin_subview_state->handle_cursor_left_press();
+}
+
+void PluginSubview::set_state(boost::shared_ptr<PluginSubviewState> new_state)
+{
+ _plugin_subview_state = new_state;
+
+ const uint32_t num_strips = _strips_over_all_surfaces.size();
+ for (uint32_t strip_index = 0; strip_index < num_strips; strip_index++)
+ {
+ Strip* strip = 0;
+ Pot* vpot = 0;
+ std::string* pending_display = 0;
+ if (!retrieve_pointers(&strip, &vpot, &pending_display, strip_index))
+ {
+ return;
+ }
+ _plugin_subview_state->setup_vpot(strip, vpot, pending_display, strip_index, _subview_stripable);
+ }
+}
+
+
+
+
+PluginSubviewState::PluginSubviewState(PluginSubview& context)
+ : _context(context)
+ , _bank_size(context.mcp().n_strips())
+ , _current_bank(0)
+{
+}
+
+PluginSubviewState::~PluginSubviewState()
+{}
+
+std::string
+PluginSubviewState::shorten_display_text(const std::string& text, std::string::size_type target_length)
+{
+ if (text.length() <= target_length) {
+ return text;
+ }
+
+ return PBD::short_version (text, target_length);
+}
+
+bool PluginSubviewState::handle_cursor_right_press()
+{
+ _current_bank = _current_bank + 1;
+ bank_changed();
+ return true;
+}
+
+bool PluginSubviewState::handle_cursor_left_press()
+{
+ if (_current_bank >= 1)
+ {
+ _current_bank = _current_bank - 1;
+ }
+ bank_changed();
+ return true;
+}
+
+uint32_t PluginSubviewState::calculate_virtual_strip_position(uint32_t strip_index) const
+{
+ return _current_bank * _bank_size + strip_index;
+}
+
+
+
+PluginSelect::PluginSelect(PluginSubview& context)
+ : PluginSubviewState(context)
+{}
+
+PluginSelect::~PluginSelect()
+{}
+
+void PluginSelect::setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2],
+ uint32_t global_strip_position,
+ boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+{
+ if (!subview_stripable) {
+ return;
+ }
+
+ boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (subview_stripable);
+ if (!route) {
+ return;
+ }
+
+ uint32_t virtual_strip_position = calculate_virtual_strip_position(global_strip_position);
+
+ boost::shared_ptr<Processor> plugin = route->nth_plugin(virtual_strip_position);
+
+ if (plugin) {
+ DEBUG_TRACE (DEBUG::MackieControl, string_compose ("plugin of strip %1 is %2\n", global_strip_position, plugin->display_name()));
+ pending_display[0] = string_compose("Ins%1Pl", virtual_strip_position + 1);
+ pending_display[1] = PluginSubviewState::shorten_display_text(plugin->display_name(), 6);
+ }
+ else {
+ pending_display[0] = "";
+ pending_display[1] = "";
+ }
+}
+
+void PluginSelect::handle_vselect_event(uint32_t global_strip_position,
+ boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+{
+ /* PluginSelect mode: press selects the plugin shown on the strip's LCD */
+ if (!subview_stripable) {
+ return;
+ }
+
+ boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (subview_stripable);
+ if (!route) {
+ return;
+ }
+
+ uint32_t virtual_strip_position = calculate_virtual_strip_position(global_strip_position);
+
+ boost::shared_ptr<Processor> processor = route->nth_plugin(virtual_strip_position);
+ boost::shared_ptr<PluginInsert> plugin = boost::dynamic_pointer_cast<PluginInsert>(processor);
+ processor->ShowUI();
+ if (plugin) {
+ _context.set_state(boost::make_shared<PluginEdit>(_context, boost::weak_ptr<PluginInsert>(plugin)));
+ }
+}
+
+void PluginSelect::bank_changed()
+{
+ _context.mcp().redisplay_subview_mode();
+}
+
+
+
+PluginEdit::PluginEdit(PluginSubview& context, boost::weak_ptr<PluginInsert> weak_subview_plugin_insert)
+ : PluginSubviewState(context)
+ , _weak_subview_plugin_insert(weak_subview_plugin_insert)
+{
+ try {
+ init();
+ }
+ catch (...) {
+ throw failed_constructor();
+ }
+}
+
+PluginEdit::~PluginEdit()
+{}
+
+void PluginEdit::init()
+{
+ boost::shared_ptr<PluginInsert> plugin_insert = _weak_subview_plugin_insert.lock();
+ _weak_subview_plugin = boost::weak_ptr<ARDOUR::Plugin>(plugin_insert->plugin());
+ boost::shared_ptr<ARDOUR::Plugin> subview_plugin = _weak_subview_plugin.lock();
+ _plugin_input_parameter_indices.clear();
+
+ if (!subview_plugin) {
+ return;
+ }
+
+ bool ok = false;
+ // put only input controls into a vector
+ uint32_t nplug_params = subview_plugin->parameter_count();
+ for (uint32_t ppi = 0; ppi < nplug_params; ++ppi) {
+ uint32_t controlid = subview_plugin->nth_parameter(ppi, ok);
+ if (!ok) {
+ continue;
+ }
+ if (subview_plugin->parameter_is_input(controlid)) {
+ _plugin_input_parameter_indices.push_back(ppi);
+ }
+ }
+}
+
+boost::shared_ptr<AutomationControl> PluginEdit::parameter_control(uint32_t global_strip_position) const
+{
+ uint32_t virtual_strip_position = calculate_virtual_strip_position(global_strip_position);
+ if (virtual_strip_position >= _plugin_input_parameter_indices.size()) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+
+ boost::shared_ptr<PluginInsert> plugin_insert = _weak_subview_plugin_insert.lock();
+ boost::shared_ptr<ARDOUR::Plugin> subview_plugin = _weak_subview_plugin.lock();
+ if (!plugin_insert || !subview_plugin) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+
+ uint32_t plugin_parameter_index = _plugin_input_parameter_indices[virtual_strip_position];
+ bool ok = false;
+ uint32_t controlid = subview_plugin->nth_parameter(plugin_parameter_index, ok);
+ if (!ok) {
+ return boost::shared_ptr<AutomationControl>();
+ }
+ return plugin_insert->automation_control(Evoral::Parameter(PluginAutomation, 0, controlid));
+}
+
+bool PluginEdit::plugin_went_away() const
+{
+ // is shared_ptr reset?
+ boost::shared_ptr<PluginInsert> plugin_insert = _weak_subview_plugin_insert.lock();
+ boost::shared_ptr<ARDOUR::Plugin> subview_plugin = _weak_subview_plugin.lock();
+ if (!plugin_insert || !subview_plugin) {
+ return true;
+ }
+
+ // is plugin not registered with stripable any more?
+ boost::shared_ptr<Route> route = boost::dynamic_pointer_cast<Route> (_context.subview_stripable());
+ if (!route) {
+ return true;
+ }
+
+ if (!route->processor_by_id(plugin_insert->id())) {
+ // plugin_insert is not registered with route any more -> it was removed
+ return true;
+ }
+
+ return false;
+}
+
+void PluginEdit::switch_to_plugin_select_state()
+{
+ _context.set_state(boost::make_shared<PluginSelect>(_context));
+}
+
+void PluginEdit::setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2],
+ uint32_t global_strip_position,
+ boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+{
+ if (plugin_went_away()) {
+ switch_to_plugin_select_state();
+ return;
+ }
+
+ boost::shared_ptr<AutomationControl> c = parameter_control(global_strip_position);
+
+ if (!c) {
+ vpot->set_control (boost::shared_ptr<AutomationControl>());
+ pending_display[0] = std::string();
+ pending_display[1] = std::string();
+ return;
+ }
+
+ c->Changed.connect (_context.subview_connections(), MISSING_INVALIDATOR, boost::bind (&PluginEdit::notify_parameter_change, this, strip, vpot, pending_display, global_strip_position), ui_context());
+ vpot->set_control (c);
+ pending_display[0] = PluginSubviewState::shorten_display_text(c->desc().label, 6);
+ notify_parameter_change (strip, vpot, pending_display, global_strip_position);
+}
+
+
+void PluginEdit::notify_parameter_change(Strip* strip, Pot* vpot, std::string pending_display[2], uint32_t global_strip_position)
+{
+ boost::shared_ptr<AutomationControl> control = parameter_control(global_strip_position);
+ if (!control)
+ {
+ return;
+ }
+
+ float val = control->get_value();
+ _context.do_parameter_display(pending_display[1], control->desc(), val, strip, false);
+
+ if (vpot->control() == control) {
+ /* update pot/encoder */
+ strip->surface()->write(vpot->set (control->internal_to_interface (val), true, Pot::wrap));
+ }
+}
+
+void PluginEdit::handle_vselect_event(uint32_t global_strip_position, boost::shared_ptr<ARDOUR::Stripable> subview_stripable)
+{
+}
+
+void PluginEdit::bank_changed()
+{
+ _context.mcp().redisplay_subview_mode();
+}
diff --git a/libs/surfaces/mackie/subview.h b/libs/surfaces/mackie/subview.h
new file mode 100644
index 0000000000..1cce051842
--- /dev/null
+++ b/libs/surfaces/mackie/subview.h
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2006-2007 John Anderson
+ * Copyright (C) 2012-2015 Paul Davis <paul@linuxaudiosystems.com>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __ardour_mackie_control_protocol_subview_h__
+#define __ardour_mackie_control_protocol_subview_h__
+
+#include <boost/smart_ptr.hpp>
+
+#include "ardour/types.h"
+
+#include "subview_modes.h"
+
+namespace ArdourSurface {
+
+class MackieControlProtocol;
+
+namespace Mackie {
+
+class Pot;
+class Strip;
+class Subview;
+class Surface;
+
+class SubviewFactory {
+ public:
+ static SubviewFactory* instance();
+
+ boost::shared_ptr<Subview> create_subview(SubViewMode svm,
+ MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ protected:
+ SubviewFactory();
+ private:
+ static SubviewFactory* _instance;
+};
+
+
+/**
+ This implements the subviews of the Mackie control in a Strategy pattern
+*/
+class Subview {
+ public:
+ Subview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual ~Subview();
+
+ virtual SubViewMode subview_mode () const = 0;
+ virtual void update_global_buttons() = 0;
+ virtual bool permit_flipping_faders_and_pots() { return false; }
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2]) = 0;
+ virtual void handle_vselect_event(uint32_t global_strip_position);
+ // returns true if press was handled in the subview, default is false
+ virtual bool handle_cursor_right_press() { return false; }
+ // returns true if press was handled in the subview, default is false
+ virtual bool handle_cursor_left_press() { return false; }
+
+ static bool subview_mode_would_be_ok (SubViewMode, boost::shared_ptr<ARDOUR::Stripable>, std::string& reason_why_not);
+ boost::shared_ptr<ARDOUR::Stripable> subview_stripable() const { return _subview_stripable; }
+
+ void notify_subview_stripable_deleted ();
+ MackieControlProtocol& mcp() { return _mcp; }
+
+ PBD::ScopedConnectionList& subview_stripable_connections() { return _subview_stripable_connections; }
+ PBD::ScopedConnectionList& subview_connections() { return _subview_connections; }
+
+ void do_parameter_display(std::string& display, const ARDOUR::ParameterDescriptor& pd, float param_val, Strip* strip, bool screen_hold);
+
+ protected:
+ void init_strip_vectors();
+ void store_pointers(Strip* strip, Pot* vpot, std::string* pending_display, uint32_t global_strip_position);
+ bool retrieve_pointers(Strip** strip, Pot** vpot, std::string** pending_display, uint32_t global_strip_position);
+
+ MackieControlProtocol& _mcp;
+ boost::shared_ptr<ARDOUR::Stripable> _subview_stripable;
+ PBD::ScopedConnectionList _subview_stripable_connections;
+
+ std::vector<Strip*> _strips_over_all_surfaces;
+ std::vector<Pot*> _strip_vpots_over_all_surfaces;
+ std::vector<std::string*> _strip_pending_displays_over_all_surfaces;
+ PBD::ScopedConnectionList _subview_connections;
+ private:
+ void reset_all_vpot_controls();
+};
+
+class NoneSubview : public Subview {
+ public:
+ NoneSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual ~NoneSubview();
+
+ virtual SubViewMode subview_mode () const { return SubViewMode::None; }
+ static bool subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not);
+
+ virtual void update_global_buttons();
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2]);
+};
+
+class EQSubview : public Subview {
+ public:
+ EQSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual ~EQSubview();
+
+ virtual SubViewMode subview_mode () const { return SubViewMode::EQ; }
+ static bool subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not);
+ virtual void update_global_buttons();
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2]);
+ void notify_change (boost::weak_ptr<ARDOUR::AutomationControl>, uint32_t global_strip_position, bool force);
+};
+
+class DynamicsSubview : public Subview {
+ public:
+ DynamicsSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual ~DynamicsSubview();
+
+ virtual SubViewMode subview_mode () const { return SubViewMode::Dynamics; }
+ static bool subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not);
+ virtual void update_global_buttons();
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2]);
+ void notify_change (boost::weak_ptr<ARDOUR::AutomationControl>, uint32_t global_strip_position, bool force, bool propagate_mode_change);
+};
+
+class SendsSubview : public Subview {
+ public:
+ SendsSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual ~SendsSubview();
+
+ virtual SubViewMode subview_mode () const { return SubViewMode::Sends; }
+ static bool subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not);
+ virtual void update_global_buttons();
+ virtual bool permit_flipping_faders_and_pots() { return true; }
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2]);
+ void notify_send_level_change (uint32_t global_strip_position, bool force);
+
+ virtual void handle_vselect_event(uint32_t global_strip_position);
+};
+
+class TrackViewSubview : public Subview {
+ public:
+ TrackViewSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual ~TrackViewSubview();
+
+ virtual SubViewMode subview_mode () const { return SubViewMode::TrackView; }
+ static bool subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not);
+ virtual void update_global_buttons();
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2]);
+ void notify_change (ARDOUR::AutomationType, uint32_t global_strip_position, bool force);
+};
+
+class PluginSubviewState;
+
+class PluginSubview : public Subview {
+ public:
+ PluginSubview(MackieControlProtocol& mcp, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual ~PluginSubview();
+
+ virtual SubViewMode subview_mode () const { return SubViewMode::Plugin; }
+ static bool subview_mode_would_be_ok (boost::shared_ptr<ARDOUR::Stripable> r, std::string& reason_why_not);
+ virtual void update_global_buttons();
+ virtual bool permit_flipping_faders_and_pots();
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2]);
+ virtual void handle_vselect_event(uint32_t global_strip_position);
+ virtual bool handle_cursor_right_press();
+ virtual bool handle_cursor_left_press();
+
+ void set_state(boost::shared_ptr<PluginSubviewState> new_state);
+
+ protected:
+ void connect_processors_changed_signal();
+ void handle_processors_changed();
+
+ boost::shared_ptr<PluginSubviewState> _plugin_subview_state;
+};
+
+class PluginSubviewState {
+ public:
+ PluginSubviewState(PluginSubview& context);
+ virtual ~PluginSubviewState();
+
+ virtual bool permit_flipping_faders_and_pots() { return false; }
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2],
+ uint32_t global_strip_position,
+ boost::shared_ptr<ARDOUR::Stripable> subview_stripable) = 0;
+ virtual void handle_vselect_event(uint32_t global_strip_position, boost::shared_ptr<ARDOUR::Stripable> subview_stripable) = 0;
+ static std::string shorten_display_text(const std::string& text, std::string::size_type target_length);
+ virtual bool handle_cursor_right_press();
+ virtual bool handle_cursor_left_press();
+ virtual void bank_changed() = 0;
+
+ protected:
+ uint32_t calculate_virtual_strip_position(uint32_t strip_index) const;
+
+ PluginSubview& _context;
+ const uint32_t _bank_size;
+ uint32_t _current_bank;
+};
+
+class PluginSelect : public PluginSubviewState {
+ public:
+ PluginSelect(PluginSubview& context);
+ virtual ~PluginSelect();
+
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2],
+ uint32_t global_strip_position,
+ boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual void handle_vselect_event(uint32_t global_strip_position, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual void bank_changed();
+};
+
+class PluginEdit : public PluginSubviewState {
+ public:
+ PluginEdit(PluginSubview& context, boost::weak_ptr<ARDOUR::PluginInsert> weak_subview_plugin);
+ virtual ~PluginEdit();
+
+ virtual bool permit_flipping_faders_and_pots() { return true; }
+ virtual void setup_vpot(
+ Strip* strip,
+ Pot* vpot,
+ std::string pending_display[2],
+ uint32_t global_strip_position,
+ boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual void handle_vselect_event(uint32_t global_strip_position, boost::shared_ptr<ARDOUR::Stripable> subview_stripable);
+ virtual void bank_changed();
+
+ void notify_parameter_change(Strip* strip, Pot* vpot, std::string pending_display[2], uint32_t global_strip_position);
+ void init();
+ bool plugin_went_away() const;
+ void switch_to_plugin_select_state();
+
+ boost::shared_ptr<ARDOUR::AutomationControl> parameter_control(uint32_t global_strip_position) const;
+
+ boost::weak_ptr<ARDOUR::PluginInsert> _weak_subview_plugin_insert;
+ boost::weak_ptr<ARDOUR::Plugin> _weak_subview_plugin;
+ std::vector<uint32_t> _plugin_input_parameter_indices;
+};
+
+}
+}
+
+#endif /* __ardour_mackie_control_protocol_subview_h__ */
diff --git a/libs/surfaces/mackie/subview_modes.h b/libs/surfaces/mackie/subview_modes.h
new file mode 100644
index 0000000000..f2b34da52a
--- /dev/null
+++ b/libs/surfaces/mackie/subview_modes.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2006-2007 John Anderson
+ * Copyright (C) 2012-2015 Paul Davis <paul@linuxaudiosystems.com>
+ *
+ * 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __ardour_mackie_control_protocol_subview_modes_h__
+#define __ardour_mackie_control_protocol_subview_modes_h__
+
+namespace ArdourSurface {
+
+namespace Mackie {
+
+enum SubViewMode {
+ None,
+ EQ,
+ Dynamics,
+ Sends,
+ TrackView,
+ Plugin,
+};
+
+}
+}
+
+#endif /* __ardour_mackie_control_protocol_subview_modes_h__ */
diff --git a/libs/surfaces/mackie/wscript b/libs/surfaces/mackie/wscript
index fa18995999..2ed12fb10b 100644
--- a/libs/surfaces/mackie/wscript
+++ b/libs/surfaces/mackie/wscript
@@ -31,6 +31,7 @@ def build(bld):
midi_byte_array.cc
pot.cc
strip.cc
+ subview.cc
surface.cc
surface_port.cc
types.cc