diff options
Diffstat (limited to 'libs')
-rw-r--r-- | libs/surfaces/mackie/mackie_control_protocol.cc | 163 | ||||
-rw-r--r-- | libs/surfaces/mackie/mackie_control_protocol.h | 22 | ||||
-rw-r--r-- | libs/surfaces/mackie/mcp_buttons.cc | 30 | ||||
-rw-r--r-- | libs/surfaces/mackie/strip.cc | 622 | ||||
-rw-r--r-- | libs/surfaces/mackie/strip.h | 21 | ||||
-rw-r--r-- | libs/surfaces/mackie/subview.cc | 1233 | ||||
-rw-r--r-- | libs/surfaces/mackie/subview.h | 279 | ||||
-rw-r--r-- | libs/surfaces/mackie/subview_modes.h | 39 | ||||
-rw-r--r-- | libs/surfaces/mackie/wscript | 1 |
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 |