X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fsurfaces%2Ffaderport8%2Ffaderport8.cc;h=5e5cf498f739ed0d2b0037f1f3a9157231d9e38e;hb=7b1a875f9c736b419285318147b3dc6b9c0a0e00;hp=802942cbe780b0c41e67b38e6066c6ea2ab2d217;hpb=bce08cf4f37b2bbd33345fb7296a6ced04eb652a;p=ardour.git diff --git a/libs/surfaces/faderport8/faderport8.cc b/libs/surfaces/faderport8/faderport8.cc index 802942cbe7..5e5cf498f7 100644 --- a/libs/surfaces/faderport8/faderport8.cc +++ b/libs/surfaces/faderport8/faderport8.cc @@ -1,20 +1,21 @@ /* - * Copyright (C) 2017 Robin Gareus - * Copyright (C) 2015 Paul Davis + * Copyright (C) 2017-2018 Ben Loftis + * Copyright (C) 2017-2018 Robin Gareus + * Copyright (C) 2017 Paul Davis * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. + * This program is 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. + * 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 @@ -37,22 +38,25 @@ #include "ardour/debug.h" #include "ardour/midi_track.h" #include "ardour/midiport_manager.h" +#include "ardour/panner_shell.h" +#include "ardour/plugin.h" #include "ardour/plugin_insert.h" #include "ardour/processor.h" #include "ardour/rc_configuration.h" #include "ardour/route.h" #include "ardour/session.h" #include "ardour/session_configuration.h" +#include "ardour/tempo.h" #include "ardour/vca.h" #include "faderport8.h" using namespace ARDOUR; -using namespace ArdourSurface; using namespace PBD; using namespace Glib; using namespace std; -using namespace ArdourSurface::FP8Types; +using namespace ArdourSurface::FP_NAMESPACE; +using namespace ArdourSurface::FP_NAMESPACE::FP8Types; #include "pbd/i18n.h" @@ -84,24 +88,47 @@ debug_2byte_msg (std::string const& msg, int b0, int b1) } FaderPort8::FaderPort8 (Session& s) +#ifdef FADERPORT16 + : ControlProtocol (s, _("PreSonus FaderPort16")) +#elif defined FADERPORT2 + : ControlProtocol (s, _("PreSonus FaderPort2")) +#else : ControlProtocol (s, _("PreSonus FaderPort8")) +#endif , AbstractUI (name()) , _connection_state (ConnectionState (0)) , _device_active (false) , _ctrls (*this) - , _channel_off (0) , _plugin_off (0) , _parameter_off (0) + , _show_presets (false) + , _showing_well_known (0) + , _timer_divider (0) , _blink_onoff (false) , _shift_lock (false) , _shift_pressed (0) , gui (0) + , _link_enabled (false) + , _link_locked (false) + , _chan_locked (false) + , _clock_mode (1) + , _scribble_mode (2) + , _two_line_text (false) + , _auto_pluginui (true) { boost::shared_ptr inp; boost::shared_ptr outp; +#ifdef FADERPORT16 + inp = AudioEngine::instance()->register_input_port (DataType::MIDI, "FaderPort16 Recv", true); + outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "FaderPort16 Send", true); +#elif defined FADERPORT2 + inp = AudioEngine::instance()->register_input_port (DataType::MIDI, "FaderPort2 Recv", true); + outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "FaderPort2 Send", true); +#else inp = AudioEngine::instance()->register_input_port (DataType::MIDI, "FaderPort8 Recv", true); outp = AudioEngine::instance()->register_output_port (DataType::MIDI, "FaderPort8 Send", true); +#endif _input_port = boost::dynamic_pointer_cast(inp); _output_port = boost::dynamic_pointer_cast(outp); @@ -109,8 +136,16 @@ FaderPort8::FaderPort8 (Session& s) throw failed_constructor(); } +#ifdef FADERPORT16 + _input_bundle.reset (new ARDOUR::Bundle (_("FaderPort16 (Receive)"), true)); + _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort16 (Send)"), false)); +#elif defined FADERPORT2 + _input_bundle.reset (new ARDOUR::Bundle (_("FaderPort2 (Receive)"), true)); + _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort2 (Send)"), false)); +#else _input_bundle.reset (new ARDOUR::Bundle (_("FaderPort8 (Receive)"), true)); - _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort8 (Send) "), false)); + _output_bundle.reset (new ARDOUR::Bundle (_("FaderPort8 (Send)"), false)); +#endif _input_bundle->add_channel ( inp->name(), @@ -124,39 +159,44 @@ FaderPort8::FaderPort8 (Session& s) session->engine().make_port_name_non_relative (outp->name()) ); - ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::connection_handler, this, _1, _2, _3, _4, _5), this); - - StripableSelectionChanged.connect (selection_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::gui_track_selection_changed, this), this); + ARDOUR::AudioEngine::instance()->PortConnectedOrDisconnected.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::connection_handler, this, _2, _4), this); + ARDOUR::AudioEngine::instance()->Stopped.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::engine_reset, this), this); + ARDOUR::Port::PortDrop.connect (port_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::engine_reset, this), this); + /* bind button events to call libardour actions */ setup_actions (); + _ctrls.FaderModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::notify_fader_mode_changed, this)); - _ctrls.MixModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::assign_strips, this, true)); + _ctrls.MixModeChanged.connect_same_thread (modechange_connections, boost::bind (&FaderPort8::assign_strips, this)); } FaderPort8::~FaderPort8 () { - cerr << "~FP8\n"; - disconnected (); - close (); + /* this will be called from the main UI thread. during Session::destroy(). + * There can be concurrent activity from BaseUI::main_thread -> AsyncMIDIPort + * -> MIDI::Parser::signal -> ... to any of the midi_connections + * + * stop event loop early and join thread */ + stop (); if (_input_port) { DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("unregistering input port %1\n", boost::shared_ptr(_input_port)->name())); + Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock()); AudioEngine::instance()->unregister_port (_input_port); _input_port.reset (); } + disconnected (); // zero faders, turn lights off, clear strips + if (_output_port) { _output_port->drain (10000, 250000); /* check every 10 msecs, wait up to 1/4 second for the port to drain */ DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("unregistering output port %1\n", boost::shared_ptr(_output_port)->name())); + Glib::Threads::Mutex::Lock em (AudioEngine::instance()->process_lock()); AudioEngine::instance()->unregister_port (_output_port); _output_port.reset (); } tear_down_gui (); - - /* stop event loop */ - DEBUG_TRACE (DEBUG::FaderPort8, "BaseUI::quit ()\n"); - BaseUI::quit (); } /* **************************************************************************** @@ -181,47 +221,59 @@ FaderPort8::do_request (FaderPort8Request* req) call_slot (MISSING_INVALIDATOR, req->the_slot); } else if (req->type == Quit) { stop (); + disconnected (); } } -int +void FaderPort8::stop () { + DEBUG_TRACE (DEBUG::FaderPort8, "BaseUI::quit ()\n"); BaseUI::quit (); - return 0; + close (); // drop references, disconnect from session signals } void FaderPort8::thread_init () { - struct sched_param rtparam; - pthread_set_name (event_loop_name().c_str()); PBD::notify_event_loops_about_thread_creation (pthread_self(), event_loop_name(), 2048); ARDOUR::SessionEvent::create_per_thread_pool (event_loop_name(), 128); - memset (&rtparam, 0, sizeof (rtparam)); - rtparam.sched_priority = 9; /* XXX should be relative to audio (JACK) thread */ - - if (pthread_setschedparam (pthread_self(), SCHED_FIFO, &rtparam) != 0) { - // do we care? not particularly. - } + set_thread_priority (); } bool FaderPort8::periodic () { - /* prepare TC display -- handled by stripable Periodic () */ - if (_ctrls.display_timecode ()) { - // TODO allow BBT, HHMMSS - // used in FP8Strip::periodic_update_timecode + /* prepare TC display -- handled by stripable Periodic () + * in FP8Strip::periodic_update_timecode + */ + if (_ctrls.display_timecode () && clock_mode ()) { Timecode::Time TC; session->timecode_time (TC); _timecode = Timecode::timecode_format_time(TC); + + char buf[16]; + Timecode::BBT_Time BBT = session->tempo_map ().bbt_at_sample (session->transport_sample ()); + snprintf (buf, sizeof (buf), + " %02" PRIu32 "|%02" PRIu32 "|%02" PRIu32 "|%02" PRIu32, + BBT.bars % 100, BBT.beats %100, + (BBT.ticks/ 100) %100, BBT.ticks %100); + _musical_time = std::string (buf); } else { _timecode.clear (); + _musical_time.clear (); + } + +#ifdef FADERPORT16 + /* every second, send "running" */ + if (++_timer_divider == 10) { + _timer_divider = 0; + tx_midi3 (0xa0, 0x00, 0x00); } +#endif /* update stripables */ Periodic (); @@ -253,8 +305,7 @@ FaderPort8::set_active (bool yn) BaseUI::run (); connect_session_signals (); } else { - BaseUI::quit (); - close (); + stop (); } ControlProtocol::set_active (yn); @@ -265,13 +316,14 @@ FaderPort8::set_active (bool yn) void FaderPort8::close () { + DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::close\n"); stop_midi_handling (); session_connections.drop_connections (); - automation_state_connections.drop_connections (); + route_state_connections.drop_connections (); assigned_stripable_connections.drop_connections (); _assigned_strips.clear (); drop_ctrl_connections (); - port_connection.disconnect (); + port_connections.drop_connections (); selection_connection.disconnect (); } @@ -290,13 +342,21 @@ void FaderPort8::connected () { DEBUG_TRACE (DEBUG::FaderPort8, "initializing\n"); + assert (!_device_active); + + if (_device_active) { + stop_midi_handling (); // re-init + } + // ideally check firmware version >= 1.01 (USB bcdDevice 0x0101) (vendor 0x194f prod 0x0202) // but we don't have a handle to the underlying USB device here. - _channel_off = _plugin_off = _parameter_off = 0; + memset (_channel_off, 0, sizeof (_channel_off)); + _plugin_off = _parameter_off = 0; _blink_onoff = false; _shift_lock = false; _shift_pressed = 0; + _timer_divider = 0; start_midi_handling (); _ctrls.initialize (); @@ -311,7 +371,7 @@ FaderPort8::connected () tx_midi3 (0x90, 0x46, 0x00); send_session_state (); - assign_strips (true); + assign_strips (); Glib::RefPtr blink_timer = Glib::TimeoutSource::create (200); @@ -329,15 +389,25 @@ FaderPort8::disconnected () { stop_midi_handling (); if (_device_active) { - for (uint8_t id = 0; id < 8; ++id) { + for (uint8_t id = 0; id < N_STRIPS; ++id) { _ctrls.strip(id).unset_controllables (); } _ctrls.all_lights_off (); } } +void +FaderPort8::engine_reset () +{ + /* Port::PortDrop is called when the engine is halted or stopped */ + DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::engine_reset\n"); + _connection_state = 0; + _device_active = false; + disconnected (); +} + bool -FaderPort8::connection_handler (boost::weak_ptr, std::string name1, boost::weak_ptr, std::string name2, bool yn) +FaderPort8::connection_handler (std::string name1, std::string name2) { #ifdef VERBOSE_DEBUG DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::connection_handler: start\n"); @@ -350,13 +420,21 @@ FaderPort8::connection_handler (boost::weak_ptr, std::string name1 string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr(_output_port)->name()); if (ni == name1 || ni == name2) { - if (yn) { + DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("Connection notify %1 and %2\n", name1, name2)); + if (_input_port->connected ()) { + if (_connection_state & InputConnected) { + return false; + } _connection_state |= InputConnected; } else { _connection_state &= ~InputConnected; } } else if (no == name1 || no == name2) { - if (yn) { + DEBUG_TRACE (DEBUG::FaderPort8, string_compose ("Connection notify %1 and %2\n", name1, name2)); + if (_output_port->connected ()) { + if (_connection_state & OutputConnected) { + return false; + } _connection_state |= OutputConnected; } else { _connection_state &= ~OutputConnected; @@ -382,7 +460,9 @@ FaderPort8::connection_handler (boost::weak_ptr, std::string name1 } else { DEBUG_TRACE (DEBUG::FaderPort8, "Device disconnected (input or output or both) or not yet fully connected\n"); - disconnected (); + if (_device_active) { + disconnected (); + } _device_active = false; } @@ -416,7 +496,7 @@ FaderPort8::midi_input_handler (Glib::IOCondition ioc, boost::weak_ptr port (wport.lock()); - if (!port) { + if (!port || !_input_port) { return false; } @@ -434,7 +514,7 @@ FaderPort8::midi_input_handler (Glib::IOCondition ioc, boost::weak_ptr(port)->name())); #endif - framepos_t now = session->engine().sample_time(); + samplepos_t now = session->engine().sample_time(); port->parse (now); } @@ -508,13 +588,25 @@ void FaderPort8::controller_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb) { debug_2byte_msg ("CC", tb->controller_number, tb->value); - // encoder - // val Bit 7 = direction, Bits 0-6 = number of steps + /* encoder + * val Bit 6 = direction, Bits 0-5 = number of steps + */ + static const uint8_t dir_mask = 0x40; + static const uint8_t step_mask = 0x3f; + if (tb->controller_number == 0x3c) { - encoder_navigate (tb->value & 0x40 ? true : false, tb->value & 0x3f); + encoder_navigate (tb->value & dir_mask ? true : false, tb->value & step_mask); } if (tb->controller_number == 0x10) { - encoder_parameter (tb->value & 0x40 ? true : false, tb->value & 0x3f); +#ifdef FADERPORT2 + if (_ctrls.nav_mode() == NavPan) { + encoder_parameter (tb->value & dir_mask ? true : false, tb->value & step_mask); + } else { + encoder_navigate (tb->value & dir_mask ? true : false, tb->value & step_mask); + } +#else + encoder_parameter (tb->value & dir_mask ? true : false, tb->value & step_mask); +#endif } } @@ -524,7 +616,12 @@ FaderPort8::note_on_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb) debug_2byte_msg ("ON", tb->note_number, tb->velocity); /* fader touch */ - if (tb->note_number >= 0x68 && tb->note_number <= 0x6f) { +#ifdef FADERPORT16 + static const uint8_t touch_id_uppper = 0x77; +#else + static const uint8_t touch_id_uppper = 0x6f; +#endif + if (tb->note_number >= 0x68 && tb->note_number <= touch_id_uppper) { _ctrls.midi_touch (tb->note_number - 0x68, tb->velocity); return; } @@ -563,7 +660,12 @@ FaderPort8::note_off_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb) { debug_2byte_msg ("OF", tb->note_number, tb->velocity); - if (tb->note_number >= 0x68 && tb->note_number <= 0x6f) { +#ifdef FADERPORT16 + static const uint8_t touch_id_uppper = 0x77; +#else + static const uint8_t touch_id_uppper = 0x6f; +#endif + if (tb->note_number >= 0x68 && tb->note_number <= touch_id_uppper) { // fader touch _ctrls.midi_touch (tb->note_number - 0x68, tb->velocity); return; @@ -656,6 +758,12 @@ FaderPort8::get_state () child->add_child_nocopy (boost::shared_ptr(_output_port)->get_state()); node.add_child_nocopy (*child); +#ifndef FADERPORT2 + node.set_property (X_("clock-mode"), _clock_mode); + node.set_property (X_("scribble-mode"), _scribble_mode); + node.set_property (X_("two-line-text"), _two_line_text); +#endif + for (UserActionMap::const_iterator i = _user_action_map.begin (); i != _user_action_map.end (); ++i) { if (i->second.empty()) { continue; @@ -665,12 +773,12 @@ FaderPort8::get_state () continue; } XMLNode* btn = new XMLNode (X_("Button")); - btn->add_property (X_("id"), name); + btn->set_property (X_("id"), name); if (!i->second.action(true).empty ()) { - btn->add_property ("press", i->second.action(true)._action_name); + btn->set_property ("press", i->second.action(true)._action_name); } if (!i->second.action(false).empty ()) { - btn->add_property ("release", i->second.action(false)._action_name); + btn->set_property ("release", i->second.action(false)._action_name); } node.add_child_nocopy (*btn); } @@ -706,6 +814,10 @@ FaderPort8::set_state (const XMLNode& node, int version) } } + node.get_property (X_("clock-mode"), _clock_mode); + node.get_property (X_("scribble-mode"), _scribble_mode); + node.get_property (X_("two-line-text"), _two_line_text); + _user_action_map.clear (); // TODO: When re-loading state w/o surface re-init becomes possible, // unset lights and reset colors of user buttons. @@ -714,23 +826,23 @@ FaderPort8::set_state (const XMLNode& node, int version) if ((*n)->name() != X_("Button")) { continue; } - XMLProperty const* prop = (*n)->property (X_("id")); - if (!prop) { + + std::string id_str; + if (!(*n)->get_property (X_("id"), id_str)) { continue; } FP8Controls::ButtonId id; - if (!_ctrls.button_name_to_enum (prop->value(), id)) { + if (!_ctrls.button_name_to_enum (id_str, id)) { continue; } - prop = (*n)->property (X_("press")); - if (prop) { - set_button_action (id, true, prop->value()); + std::string action_str; + if ((*n)->get_property (X_("press"), action_str)) { + set_button_action (id, true, action_str); } - prop = (*n)->property (X_("release")); - if (prop) { - set_button_action (id, false, prop->value()); + if ((*n)->get_property (X_("release"), action_str)) { + set_button_action (id, false, action_str); } } @@ -805,52 +917,6 @@ static bool flt_instrument (boost::shared_ptr s) { return 0 != r->the_instrument (); } -struct FP8SortByNewDisplayOrder -{ - // return (a < b) - bool operator () (const boost::shared_ptr & a, const boost::shared_ptr & b) const - { - if (a->presentation_info().flags () == b->presentation_info().flags ()) { - return a->presentation_info().order() < b->presentation_info().order(); - } - - int cmp_a = 0; - int cmp_b = 0; - - if (a->presentation_info().flags () & ARDOUR::PresentationInfo::VCA) { - cmp_a = 1; - } -#ifdef MIXBUS - else if (a->presentation_info().flags () & ARDOUR::PresentationInfo::MasterOut) { - cmp_a = 3; - } - else if (a->presentation_info().flags () & ARDOUR::PresentationInfo::Mixbus || a->mixbus()) { - cmp_a = 2; - } -#endif - - if (b->presentation_info().flags () & ARDOUR::PresentationInfo::VCA) { - cmp_b = 1; - } -#ifdef MIXBUS - else if (b->presentation_info().flags () & ARDOUR::PresentationInfo::MasterOut) { - cmp_b = 3; - } - else if (b->presentation_info().flags () & ARDOUR::PresentationInfo::Mixbus || b->mixbus()) { - cmp_b = 2; - } -#endif - -#ifdef MIXBUS - // this can happen with older MB sessions (no PresentationInfo::Mixbus flag) - if (cmp_a == cmp_b) { - return a->presentation_info().order() < b->presentation_info().order(); - } -#endif - return cmp_a < cmp_b; - } -}; - void FaderPort8::filter_stripables (StripableList& strips) const { @@ -891,6 +957,9 @@ FaderPort8::filter_stripables (StripableList& strips) const case MixFX: flt = &flt_auxbus; break; + default: + assert (0); + /* fallthrough */ case MixAll: allow_master = true; flt = &flt_all; @@ -911,10 +980,10 @@ FaderPort8::filter_stripables (StripableList& strips) const strips.push_back (*s); } } - strips.sort (FP8SortByNewDisplayOrder()); + strips.sort (Stripable::Sorter(true)); } -/* Track/Pan mode: assign stripable to strips */ +/* Track/Pan mode: assign stripable to strips, Send-mode: selection */ void FaderPort8::assign_stripables (bool select_only) { @@ -925,12 +994,24 @@ FaderPort8::assign_stripables (bool select_only) set_periodic_display_mode (FP8Strip::Stripables); } +#ifdef FADERPORT2 + boost::shared_ptr s = first_selected_stripable(); + if (s) { + _ctrls.strip(0).set_stripable (s, _ctrls.fader_mode() == ModePan); + } else { + _ctrls.strip(0).unset_controllables ( FP8Strip::CTRL_ALL ); + } + return; +#endif + int n_strips = strips.size(); - _channel_off = std::min (_channel_off, n_strips - 8); - _channel_off = std::max (0, _channel_off); + int channel_off = get_channel_off (_ctrls.mix_mode ()); + channel_off = std::min (channel_off, n_strips - N_STRIPS); + channel_off = std::max (0, channel_off); + set_channel_off (_ctrls.mix_mode (), channel_off); uint8_t id = 0; - int skip = _channel_off; + int skip = channel_off; for (StripableList::const_iterator s = strips.begin(); s != strips.end(); ++s) { if (skip > 0) { --skip; @@ -946,9 +1027,17 @@ FaderPort8::assign_stripables (bool select_only) (*s)->presentation_info ().PropertyChanged.connect (assigned_stripable_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_stripable_property_changed, this, boost::weak_ptr (*s), _1), this); + if (boost::shared_ptr r = boost::dynamic_pointer_cast(*s)) { + if (r->panner_shell()) { + r->panner_shell()->Changed.connect (assigned_stripable_connections, MISSING_INVALIDATOR, + boost::bind (&FaderPort8::notify_stripable_property_changed, this, boost::weak_ptr (*s), PropertyChange()), this); + } + } + if (select_only) { + /* used in send mode */ _ctrls.strip(id).set_text_line (3, (*s)->name (), true); - _ctrls.strip(id).select_button ().set_color ((*s)->presentation_info ().color()); + _ctrls.strip(id).set_select_button_color ((*s)->presentation_info ().color()); /* update selection lights */ _ctrls.strip(id).select_button ().set_active ((*s)->is_selected ()); _ctrls.strip(id).select_button ().set_blinking (*s == first_selected_stripable ()); @@ -959,12 +1048,108 @@ FaderPort8::assign_stripables (bool select_only) boost::function cb (boost::bind (&FaderPort8::select_strip, this, boost::weak_ptr (*s))); _ctrls.strip(id).set_select_cb (cb); - if (++id == 8) { + if (++id == N_STRIPS) { break; } } - for (; id < 8; ++id) { + for (; id < N_STRIPS; ++id) { _ctrls.strip(id).unset_controllables (select_only ? (FP8Strip::CTRL_SELECT | FP8Strip::CTRL_TEXT3) : FP8Strip::CTRL_ALL); + _ctrls.strip(id).set_periodic_display_mode (FP8Strip::Stripables); + } +} + +/* **************************************************************************** + * Control Link/Lock + */ + +void +FaderPort8::unlock_link (bool drop) +{ + link_locked_connection.disconnect (); + + if (drop) { + stop_link (); // calls back here with drop = false + return; + } + + _link_locked = false; + + if (_link_enabled) { + assert (_ctrls.button (FP8Controls::BtnLink).is_active ()); + _link_control.reset (); + start_link (); // re-connect & update LED colors + } else { + _ctrls.button (FP8Controls::BtnLink).set_active (false); + _ctrls.button (FP8Controls::BtnLink).set_color (0x888888ff); + _ctrls.button (FP8Controls::BtnLock).set_active (false); + _ctrls.button (FP8Controls::BtnLock).set_color (0x888888ff); + } +} + +void +FaderPort8::lock_link () +{ + boost::shared_ptr ac = boost::dynamic_pointer_cast (_link_control.lock ()); + if (!ac) { + return; + } + ac->DropReferences.connect (link_locked_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::unlock_link, this, true), this); + + // stop watching for focus events + link_connection.disconnect (); + + _link_locked = true; + + _ctrls.button (FP8Controls::BtnLock).set_color (0x00ff00ff); + _ctrls.button (FP8Controls::BtnLink).set_color (0x00ff00ff); +} + +void +FaderPort8::stop_link () +{ + if (!_link_enabled) { + return; + } + link_connection.disconnect (); + _link_control.reset (); + _link_enabled = false; + unlock_link (); // also updates button colors +} + +void +FaderPort8::start_link () +{ + assert (!_link_locked); + + _link_enabled = true; + _ctrls.button (FP8Controls::BtnLink).set_active (true); + _ctrls.button (FP8Controls::BtnLock).set_active (true); + nofity_focus_control (_link_control); // update BtnLink, BtnLock colors + + PBD::Controllable::GUIFocusChanged.connect (link_connection, MISSING_INVALIDATOR, boost::bind (&FaderPort8::nofity_focus_control, this, _1), this); +} + + +/* **************************************************************************** + * Plugin selection and parameters + */ + +void +FaderPort8::toggle_preset_param_mode () +{ + FaderMode fadermode = _ctrls.fader_mode (); + if (fadermode != ModePlugins || _proc_params.size() == 0) { + return; + } + _show_presets = ! _show_presets; + assign_processor_ctrls (); +} + +void +FaderPort8::preset_changed () +{ + if (_show_presets) { + assign_processor_ctrls (); } } @@ -977,6 +1162,13 @@ FaderPort8::assign_processor_ctrls () } set_periodic_display_mode (FP8Strip::PluginParam); + if (_show_presets) { + if (assign_plugin_presets (_plugin_insert.lock ())) { + return; + } + _show_presets = false; + } + std::vector toggle_params; std::vector slider_params; @@ -990,39 +1182,100 @@ FaderPort8::assign_processor_ctrls () int n_parameters = std::max (toggle_params.size(), slider_params.size()); - _parameter_off = std::min (_parameter_off, n_parameters - 8); + _parameter_off = std::min (_parameter_off, n_parameters - N_STRIPS); _parameter_off = std::max (0, _parameter_off); uint8_t id = 0; for (size_t i = _parameter_off; i < (size_t)n_parameters; ++i) { if (i >= toggle_params.size ()) { - _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT0 & ~FP8Strip::CTRL_TEXT1); + _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT01 & ~FP8Strip::CTRL_TEXT2); } else if (i >= slider_params.size ()) { _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_SELECT & ~FP8Strip::CTRL_TEXT3); } else { - _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT0 & ~FP8Strip::CTRL_TEXT1 & ~FP8Strip::CTRL_SELECT & ~FP8Strip::CTRL_TEXT3); + _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT); } if (i < slider_params.size ()) { _ctrls.strip(id).set_fader_controllable (slider_params[i]->ac); - _ctrls.strip(id).set_text_line (0, slider_params[i]->name); + std::string param_name = slider_params[i]->name; + _ctrls.strip(id).set_text_line (0, param_name.substr (0, 9)); + _ctrls.strip(id).set_text_line (1, param_name.length () > 9 ? param_name.substr (9) : ""); } if (i < toggle_params.size ()) { _ctrls.strip(id).set_select_controllable (toggle_params[i]->ac); _ctrls.strip(id).set_text_line (3, toggle_params[i]->name, true); } - if (++id == 8) { - break; - } + if (++id == N_STRIPS) { + break; + } } // clear remaining - for (; id < 8; ++id) { + for (; id < N_STRIPS; ++id) { _ctrls.strip(id).unset_controllables (); } } +bool +FaderPort8::assign_plugin_presets (boost::shared_ptr pi) +{ + if (!pi) { + return false; + } + boost::shared_ptr plugin = pi->plugin (); + + std::vector presets = plugin->get_presets (); + if (presets.size () == 0) { + return false; + } + + int n_parameters = presets.size (); + + _parameter_off = std::min (_parameter_off, n_parameters - (N_STRIPS - 1)); + _parameter_off = std::max (0, _parameter_off); + Plugin::PresetRecord active = plugin->last_preset (); + + uint8_t id = 0; + for (size_t i = _parameter_off; i < (size_t)n_parameters; ++i) { + _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT01 & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT); + boost::function cb (boost::bind (&FaderPort8::select_plugin_preset, this, i)); + _ctrls.strip(id).set_select_cb (cb); + _ctrls.strip(id).select_button ().set_active (true); + if (active != presets.at(i)) { + _ctrls.strip(id).select_button ().set_color (0x0000ffff); + _ctrls.strip(id).select_button ().set_blinking (false); + } else { + _ctrls.strip(id).select_button ().set_color (0x00ffffff); + _ctrls.strip(id).select_button ().set_blinking (plugin->parameter_changed_since_last_preset ()); + } + std::string label = presets.at(i).label; + _ctrls.strip(id).set_text_line (0, label.substr (0, 9)); + _ctrls.strip(id).set_text_line (1, label.length () > 9 ? label.substr (9) : ""); + _ctrls.strip(id).set_text_line (3, "PRESET", true); + if (++id == (N_STRIPS - 1)) { + break; + } + } + + // clear remaining + for (; id < (N_STRIPS - 1); ++id) { + _ctrls.strip(id).unset_controllables (); + } + + // pin clear-preset to the last slot + assert (id == (N_STRIPS - 1)); + _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT0 & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT); + boost::function cb (boost::bind (&FaderPort8::select_plugin_preset, this, SIZE_MAX)); + _ctrls.strip(id).set_select_cb (cb); + _ctrls.strip(id).select_button ().set_blinking (false); + _ctrls.strip(id).select_button ().set_color (active.uri.empty() ? 0x00ffffff : 0x0000ffff); + _ctrls.strip(id).select_button ().set_active (true); + _ctrls.strip(id).set_text_line (0, _("(none)")); + _ctrls.strip(id).set_text_line (3, "PRESET", true); + return true; +} + void FaderPort8::build_well_known_processor_ctrls (boost::shared_ptr s, bool eq) { @@ -1031,8 +1284,17 @@ FaderPort8::build_well_known_processor_ctrls (boost::shared_ptr s, bo _proc_params.clear (); if (eq) { int cnt = s->eq_band_cnt(); - PUSH_BACK_NON_NULL ("Enable", s->eq_enable_controllable ()); - PUSH_BACK_NON_NULL ("HPF", s->eq_hpf_controllable ()); + +#ifdef MIXBUS32C + PUSH_BACK_NON_NULL ("Flt In", s->filter_enable_controllable (true)); // both HP/LP + PUSH_BACK_NON_NULL ("HP Freq", s->filter_freq_controllable (true)); + PUSH_BACK_NON_NULL ("LP Freq", s->filter_freq_controllable (false)); + PUSH_BACK_NON_NULL ("EQ In", s->eq_enable_controllable ()); +#elif defined (MIXBUS) + PUSH_BACK_NON_NULL ("EQ In", s->eq_enable_controllable ()); + PUSH_BACK_NON_NULL ("HP Freq", s->filter_freq_controllable (true)); +#endif + for (int band = 0; band < cnt; ++band) { std::string bn = s->eq_band_name (band); PUSH_BACK_NON_NULL (string_compose ("Gain %1", bn), s->eq_gain_controllable (band)); @@ -1041,8 +1303,9 @@ FaderPort8::build_well_known_processor_ctrls (boost::shared_ptr s, bo PUSH_BACK_NON_NULL (string_compose ("Shape %1", bn), s->eq_shape_controllable (band)); } } else { - PUSH_BACK_NON_NULL ("Enable", s->comp_enable_controllable ()); + PUSH_BACK_NON_NULL ("Comp In", s->comp_enable_controllable ()); PUSH_BACK_NON_NULL ("Threshold", s->comp_threshold_controllable ()); + PUSH_BACK_NON_NULL ("Makeup", s->comp_makeup_controllable ()); PUSH_BACK_NON_NULL ("Speed", s->comp_speed_controllable ()); PUSH_BACK_NON_NULL ("Mode", s->comp_mode_controllable ()); } @@ -1052,13 +1315,30 @@ void FaderPort8::select_plugin (int num) { // make sure drop_ctrl_connections() was called - assert (_proc_params.size() == 0 && _showing_well_known == 0); + assert (_proc_params.size() == 0 && _showing_well_known == 0 && _plugin_insert.expired()); boost::shared_ptr r = boost::dynamic_pointer_cast (first_selected_stripable()); if (!r) { _ctrls.set_fader_mode (ModeTrack); return; } + + // Toggle Bypass + if (shift_mod ()) { + if (num >= 0) { + boost::shared_ptr pi = boost::dynamic_pointer_cast (r->nth_plugin (num)); +#ifdef MIXBUS + if (pi && !pi->is_channelstrip () && pi->display_to_user ()) +#else + if (pi && pi->display_to_user ()) +#endif + { + pi->enable (! pi->enabled ()); + } + } + return; + } + if (num < 0) { build_well_known_processor_ctrls (r, num == -1); assign_processor_ctrls (); @@ -1073,6 +1353,33 @@ FaderPort8::select_plugin (int num) return; } + // disconnect signals from spill_plugins: processors_changed and ActiveChanged + processor_connections.drop_connections (); + r->DropReferences.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FP8Controls::set_fader_mode, &_ctrls, ModeTrack), this); + + boost::shared_ptr pi = boost::dynamic_pointer_cast (proc); + assert (pi); // nth_plugin() always returns a PI. + /* _plugin_insert is used for Bypass/Enable & presets */ +#ifdef MIXBUS + if (!pi->is_channelstrip () && pi->display_to_user ()) +#else + if (pi->display_to_user ()) +#endif + { + _plugin_insert = boost::weak_ptr (pi); + pi->ActiveChanged.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_plugin_active_changed, this), this); + boost::shared_ptr plugin = pi->plugin (); + + plugin->PresetAdded.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::preset_changed, this), this); + plugin->PresetRemoved.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::preset_changed, this), this); + plugin->PresetLoaded.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::preset_changed, this), this); + plugin->PresetDirty.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::preset_changed, this), this); + + if (_auto_pluginui) { + pi->ShowUI (); /* EMIT SIGNAL */ + } + } + // switching to "Mode Track" -> calls FaderPort8::notify_fader_mode_changed() // which drops the references, disconnects the signal and re-spills tracks proc->DropReferences.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FP8Controls::set_fader_mode, &_ctrls, ModeTrack), this); @@ -1092,6 +1399,28 @@ FaderPort8::select_plugin (int num) // display assign_processor_ctrls (); + notify_plugin_active_changed (); +} + +void +FaderPort8::select_plugin_preset (size_t num) +{ + assert (_proc_params.size() > 0); + boost::shared_ptr pi = _plugin_insert.lock(); + if (!pi) { + _ctrls.set_fader_mode (ModeTrack); + return; + } + if (num == SIZE_MAX) { + pi->plugin ()->clear_preset (); + } else { + std::vector presets = pi->plugin ()->get_presets (); + if (num < presets.size ()) { + pi->load_preset (presets.at (num)); + } + } + _show_presets = false; + assign_processor_ctrls (); } /* short 4 chars at most */ @@ -1140,16 +1469,18 @@ FaderPort8::spill_plugins () for (uint32_t i = 0; 0 != (proc = r->nth_plugin (i)); ++i) { if (!proc->display_to_user ()) { + continue; + } #ifdef MIXBUS - boost::shared_ptr pi = boost::dynamic_pointer_cast (proc); - if (pi->is_channelstrip ()) // don't skip MB PRE -#endif + /* don't show channelstrip plugins, use "well known" */ + if (boost::dynamic_pointer_cast (proc)->is_channelstrip ()) { continue; } +#endif int n_controls = 0; set p = proc->what_can_be_automated (); - for (set::iterator i = p.begin(); i != p.end(); ++i) { - std::string n = proc->describe_parameter (*i); + for (set::iterator j = p.begin(); j != p.end(); ++j) { + std::string n = proc->describe_parameter (*j); if (n == "hidden") { continue; } @@ -1161,7 +1492,7 @@ FaderPort8::spill_plugins () } int n_plugins = procs.size(); - int spillwidth = 8; + int spillwidth = N_STRIPS; bool have_well_known_eq = false; bool have_well_known_comp = false; @@ -1199,14 +1530,16 @@ FaderPort8::spill_plugins () _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT); _ctrls.strip(id).set_select_cb (cb); - _ctrls.strip(id).select_button ().set_color (0x00ff00ff); - _ctrls.strip(id).select_button ().set_active (true /*proc->enabled()*/); + _ctrls.strip(id).select_button ().set_color (proc->enabled () ? 0x00ff00ff : 0xff0000ff); + _ctrls.strip(id).select_button ().set_active (true); _ctrls.strip(id).select_button ().set_blinking (false); _ctrls.strip(id).set_text_line (0, proc->name()); _ctrls.strip(id).set_text_line (1, pi->plugin()->maker()); _ctrls.strip(id).set_text_line (2, plugintype (pi->type())); _ctrls.strip(id).set_text_line (3, ""); + pi->ActiveChanged.connect (processor_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::spill_plugins, this), this); + if (++id == spillwidth) { break; } @@ -1217,7 +1550,7 @@ FaderPort8::spill_plugins () } if (have_well_known_comp) { - assert (id < 8); + assert (id < N_STRIPS); boost::function cb (boost::bind (&FaderPort8::select_plugin, this, -2)); _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT); _ctrls.strip(id).set_select_cb (cb); @@ -1231,7 +1564,7 @@ FaderPort8::spill_plugins () ++id; } if (have_well_known_eq) { - assert (id < 8); + assert (id < N_STRIPS); boost::function cb (boost::bind (&FaderPort8::select_plugin, this, -1)); _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT); _ctrls.strip(id).set_select_cb (cb); @@ -1244,9 +1577,13 @@ FaderPort8::spill_plugins () _ctrls.strip(id).set_text_line (3, ""); ++id; } - assert (id == 8); + assert (id == N_STRIPS); } +/* **************************************************************************** + * Aux Sends and Mixbus assigns + */ + void FaderPort8::assign_sends () { @@ -1270,7 +1607,7 @@ FaderPort8::assign_sends () set_periodic_display_mode (FP8Strip::SendDisplay); - _plugin_off = std::min (_plugin_off, n_sends - 8); + _plugin_off = std::min (_plugin_off, n_sends - N_STRIPS); _plugin_off = std::max (0, _plugin_off); uint8_t id = 0; @@ -1285,21 +1622,21 @@ FaderPort8::assign_sends () break; } - _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT0 & ~FP8Strip::CTRL_TEXT1 & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT); + _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_FADER & ~FP8Strip::CTRL_TEXT01 & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT); _ctrls.strip(id).set_fader_controllable (send); _ctrls.strip(id).set_text_line (0, s->send_name (i)); _ctrls.strip(id).set_mute_controllable (s->send_enable_controllable (i)); - if (++id == 8) { + if (++id == N_STRIPS) { break; } } // clear remaining - for (; id < 8; ++id) { + for (; id < N_STRIPS; ++id) { _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT3 & ~FP8Strip::CTRL_SELECT); } #ifdef MIXBUS // master-assign on last solo - _ctrls.strip(7).set_solo_controllable (s->master_send_enable_controllable ()); + _ctrls.strip(N_STRIPS - 1).set_solo_controllable (s->master_send_enable_controllable ()); #endif /* set select buttons */ assigned_stripable_connections.drop_connections (); @@ -1307,21 +1644,13 @@ FaderPort8::assign_sends () assign_stripables (true); } -void -FaderPort8::set_periodic_display_mode (FP8Strip::DisplayMode m) -{ - for (uint8_t id = 0; id < 8; ++id) { - _ctrls.strip(id).set_periodic_display_mode (m); - } -} +/* **************************************************************************** + * Main stripable assignment (dispatch depending on mode) + */ void -FaderPort8::assign_strips (bool reset_bank) +FaderPort8::assign_strips () { - if (reset_bank) { - _channel_off = 0; - } - assigned_stripable_connections.drop_connections (); _assigned_strips.clear (); @@ -1330,7 +1659,7 @@ FaderPort8::assign_strips (bool reset_bank) case ModeTrack: case ModePan: assign_stripables (); - gui_track_selection_changed (); // update selection, automation-state + stripable_selection_changed (); // update selection, automation-state break; case ModePlugins: if (_proc_params.size() > 0) { @@ -1345,15 +1674,87 @@ FaderPort8::assign_strips (bool reset_bank) } } +/* **************************************************************************** + * some helper functions + */ + +void +FaderPort8::set_periodic_display_mode (FP8Strip::DisplayMode m) +{ + for (uint8_t id = 0; id < N_STRIPS; ++id) { + _ctrls.strip(id).set_periodic_display_mode (m); + } +} void FaderPort8::drop_ctrl_connections () { _proc_params.clear(); + if (_auto_pluginui) { + boost::shared_ptr pi = _plugin_insert.lock (); + if (pi) { + pi->HideUI (); /* EMIT SIGNAL */ + } + } + _plugin_insert.reset (); + _show_presets = false; processor_connections.drop_connections (); _showing_well_known = 0; + notify_plugin_active_changed (); +} + +/* functor for FP8Strip's select button */ +void +FaderPort8::select_strip (boost::weak_ptr ws) +{ + boost::shared_ptr s = ws.lock(); + if (!s) { + return; + } +#if 1 /* single exclusive selection by default, toggle via shift */ + +# if 1 /* selecting a selected strip -> move fader to unity */ + if (s == first_selected_stripable () && !shift_mod ()) { + if (_ctrls.fader_mode () == ModeTrack) { + boost::shared_ptr ac = s->gain_control (); + ac->start_touch (ac->session().transport_sample()); + ac->set_value (ac->normal (), PBD::Controllable::UseGroup); + } + return; + } +# endif + + if (shift_mod ()) { + ToggleStripableSelection (s); + } else { + SetStripableSelection (s); + } +#else + /* tri-state selection: This allows to set the "first selected" + * with a single click without clearing the selection. + * Single de/select via shift. + */ + if (shift_mod ()) { + if (s->is_selected ()) { + RemoveStripableFromSelection (s); + } else { + SetStripableSelection (s); + } + return; + } + if (s->is_selected () && s != first_selected_stripable ()) { + set_first_selected_stripable (s); + stripable_selection_changed (); + } else { + ToggleStripableSelection (s); + } +#endif } +/* **************************************************************************** + * Assigned Stripable Callbacks + */ + void FaderPort8::notify_fader_mode_changed () { @@ -1375,19 +1776,16 @@ FaderPort8::notify_fader_mode_changed () case ModeSend: _plugin_off = 0; _parameter_off = 0; + stop_link (); // force unset rec-arm button, see also FaderPort8::button_arm _ctrls.button (FP8Controls::BtnArm).set_active (false); ARMButtonChange (false); break; } - assign_strips (false); - notify_automation_mode_changed (); + assign_strips (); + notify_route_state_changed (); } -/* **************************************************************************** - * Assigned Stripable Callbacks - */ - void FaderPort8::notify_stripable_added_or_removed () { @@ -1398,43 +1796,7 @@ FaderPort8::notify_stripable_added_or_removed () * - Properties::hidden * - Properties::order */ - assign_strips (false); -} - -/* functor for FP8Strip's select button */ -void -FaderPort8::select_strip (boost::weak_ptr ws) -{ - boost::shared_ptr s = ws.lock(); - if (!s) { - return; - } -#if 1 /* single exclusive selection by default, toggle via shift */ - if (shift_mod ()) { - ToggleStripableSelection (s); - } else { - SetStripableSelection (s); - } -#else - /* tri-state selection: This allows to set the "first selected" - * with a single click without clearing the selection. - * Single de/select via shift. - */ - if (shift_mod ()) { - if (s->is_selected ()) { - RemoveStripableFromSelection (s); - } else { - SetStripableSelection (s); - } - return; - } - if (s->is_selected () && s != first_selected_stripable ()) { - set_first_selected_stripable (s); - gui_track_selection_changed (); - } else { - ToggleStripableSelection (s); - } -#endif + assign_strips (); } /* called from static PresentationInfo::Change */ @@ -1474,7 +1836,11 @@ FaderPort8::notify_stripable_property_changed (boost::weak_ptr ws, co uint8_t id = _assigned_strips[s]; if (what_changed.contains (Properties::color)) { - _ctrls.strip(id).select_button ().set_color (s->presentation_info ().color()); + _ctrls.strip(id).set_select_button_color (s->presentation_info ().color()); + } + + if (what_changed.empty ()) { + _ctrls.strip(id).set_stripable (s, _ctrls.fader_mode() == ModePan); } if (what_changed.contains (Properties::name)) { @@ -1493,10 +1859,30 @@ FaderPort8::notify_stripable_property_changed (boost::weak_ptr ws, co } } +#ifdef FADERPORT2 void -FaderPort8::gui_track_selection_changed (/*ARDOUR::StripableNotificationListPtr*/) +FaderPort8::stripable_selection_changed () { - automation_state_connections.drop_connections(); + if (!_device_active || _chan_locked) { + return; + } + route_state_connections.drop_connections (); + assign_stripables (false); + subscribe_to_strip_signals (); +} + +#else + +void +FaderPort8::stripable_selection_changed () +{ + if (!_device_active) { + /* this can be called anytime from the static + * ControlProtocol::StripableSelectionChanged + */ + return; + } + route_state_connections.drop_connections(); switch (_ctrls.fader_mode ()) { case ModePlugins: @@ -1505,6 +1891,9 @@ FaderPort8::gui_track_selection_changed (/*ARDOUR::StripableNotificationListPtr* int wk = _showing_well_known; drop_ctrl_connections (); select_plugin (wk); + } else if (_proc_params.size() == 0) { + /* selecting plugin, update available */ + spill_plugins (); } return; case ModeSend: @@ -1525,21 +1914,34 @@ FaderPort8::gui_track_selection_changed (/*ARDOUR::StripableNotificationListPtr* _ctrls.strip(id).select_button ().set_blinking (sel && s == first_selected_stripable ()); } - /* track automation-mode of primary selection */ + subscribe_to_strip_signals (); +} +#endif + +void +FaderPort8::subscribe_to_strip_signals () +{ + /* keep track of automation-mode of primary selection, shared buttons */ boost::shared_ptr s = first_selected_stripable(); if (s) { boost::shared_ptr ac; ac = s->gain_control(); if (ac && ac->alist()) { - ac->alist()->automation_state_changed.connect (automation_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_automation_mode_changed, this), this); + ac->alist()->automation_state_changed.connect (route_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_route_state_changed, this), this); } ac = s->pan_azimuth_control(); if (ac && ac->alist()) { - ac->alist()->automation_state_changed.connect (automation_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_automation_mode_changed, this), this); + ac->alist()->automation_state_changed.connect (route_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_route_state_changed, this), this); + } +#ifdef FADERPORT2 + ac = s->rec_enable_control(); + if (ac) { + ac->Changed.connect (route_state_connections, MISSING_INVALIDATOR, boost::bind (&FaderPort8::notify_route_state_changed, this), this); } +#endif } /* set lights */ - notify_automation_mode_changed (); + notify_route_state_changed (); } @@ -1564,16 +1966,18 @@ FaderPort8::move_selected_into_view () } int off = std::distance (strips.begin(), it); - if (_channel_off <= off && off < _channel_off + 8) { + int channel_off = get_channel_off (_ctrls.mix_mode ()); + if (channel_off <= off && off < channel_off + N_STRIPS) { return; } - if (_channel_off > off) { - _channel_off = off; + if (channel_off > off) { + channel_off = off; } else { - _channel_off = off - 7; + channel_off = off - (N_STRIPS - 1); } - assign_strips (false); + set_channel_off (_ctrls.mix_mode (), channel_off); + assign_strips (); } void @@ -1622,18 +2026,24 @@ FaderPort8::select_prev_next (bool next) void FaderPort8::bank (bool down, bool page) { - int dt = page ? 8 : 1; +#ifdef FADERPORT2 + // XXX this should preferably be in actions.cc + AccessAction ("Editor", down ? "select-prev-stripable" : "select-next-stripable"); + return; +#endif + + int dt = page ? N_STRIPS : 1; if (down) { dt *= -1; } - _channel_off += dt; - assign_strips (false); + set_channel_off (_ctrls.mix_mode (), get_channel_off (_ctrls.mix_mode ()) + dt); + assign_strips (); } void FaderPort8::bank_param (bool down, bool page) { - int dt = page ? 8 : 1; + int dt = page ? N_STRIPS : 1; if (down) { dt *= -1; }