X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fsurfaces%2Ffaderport8%2Ffaderport8.cc;h=7a2448e939f8088af071c5d91644a39d4da5df87;hb=82e6de3a3f63930a0d1a4316ce39d36e18d17e89;hp=5429ed29ead9e88deae052b591e27c259551b87d;hpb=43d9feabd31baaf47d5e0a1e3f1ff52be803346f;p=ardour.git diff --git a/libs/surfaces/faderport8/faderport8.cc b/libs/surfaces/faderport8/faderport8.cc index 5429ed29ea..7a2448e939 100644 --- a/libs/surfaces/faderport8/faderport8.cc +++ b/libs/surfaces/faderport8/faderport8.cc @@ -94,7 +94,7 @@ FaderPort8::FaderPort8 (Session& s) , _parameter_off (0) , _blink_onoff (false) , _shift_lock (false) - , _shift_pressed (false) + , _shift_pressed (0) , gui (0) { boost::shared_ptr inp; @@ -124,11 +124,13 @@ 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)); } @@ -136,7 +138,7 @@ FaderPort8::FaderPort8 (Session& s) FaderPort8::~FaderPort8 () { cerr << "~FP8\n"; - stop_midi_handling (); + disconnected (); close (); if (_input_port) { @@ -265,13 +267,14 @@ FaderPort8::set_active (bool yn) void FaderPort8::close () { - _assigned_strips.clear (); + DEBUG_TRACE (DEBUG::FaderPort8, "FaderPort8::close\n"); stop_midi_handling (); session_connections.drop_connections (); automation_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 +293,19 @@ 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; _blink_onoff = false; _shift_lock = false; - _shift_pressed = false; + _shift_pressed = 0; start_midi_handling (); _ctrls.initialize (); @@ -328,13 +337,26 @@ void FaderPort8::disconnected () { stop_midi_handling (); - for (uint8_t id = 0; id < 8; ++id) { - _ctrls.strip(id).unset_controllables (); + if (_device_active) { + for (uint8_t id = 0; id < 8; ++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"); @@ -347,13 +369,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; @@ -379,7 +409,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; } @@ -495,7 +527,7 @@ FaderPort8::pitchbend_handler (MIDI::Parser &, uint8_t chan, MIDI::pitchbend_t p /* fader 0..16368 (0x3ff0 -- 1024 steps) */ bool handled = _ctrls.midi_fader (chan, pb); /* if Shift key is held while moving a fader (group override), don't lock shift. */ - if (_shift_pressed && handled) { + if ((_shift_pressed > 0) && handled) { _shift_connection.disconnect (); _shift_lock = false; } @@ -528,7 +560,10 @@ FaderPort8::note_on_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb) /* special case shift */ if (tb->note_number == 0x06 || tb->note_number == 0x46) { - _shift_pressed = true; + _shift_pressed |= (tb->note_number == 0x06) ? 1 : 2; + if (_shift_pressed == 3) { + return; + } _shift_connection.disconnect (); if (_shift_lock) { _shift_lock = false; @@ -565,7 +600,10 @@ FaderPort8::note_off_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb) /* special case shift */ if (tb->note_number == 0x06 || tb->note_number == 0x46) { - _shift_pressed = false; + _shift_pressed &= (tb->note_number == 0x06) ? 2 : 1; + if (_shift_pressed > 0) { + return; + } if (_shift_lock) { return; } @@ -580,7 +618,7 @@ FaderPort8::note_off_handler (MIDI::Parser &, MIDI::EventTwoBytes* tb) bool handled = _ctrls.midi_event (tb->note_number, tb->velocity); /* if Shift key is held while activating an action, don't lock shift. */ - if (_shift_pressed && handled) { + if ((_shift_pressed > 0) && handled) { _shift_connection.disconnect (); _shift_lock = false; } @@ -656,12 +694,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); } @@ -705,23 +743,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); } } @@ -798,7 +836,7 @@ static bool flt_instrument (boost::shared_ptr s) { struct FP8SortByNewDisplayOrder { - // return (a < b) + // return strict (a < b) bool operator () (const boost::shared_ptr & a, const boost::shared_ptr & b) const { if (a->presentation_info().flags () == b->presentation_info().flags ()) { @@ -808,36 +846,34 @@ struct FP8SortByNewDisplayOrder int cmp_a = 0; int cmp_b = 0; + // see also gtk2_ardour/route_sorter.h if (a->presentation_info().flags () & ARDOUR::PresentationInfo::VCA) { - cmp_a = 1; + cmp_a = 2; } #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; + cmp_a = 1; } #endif if (b->presentation_info().flags () & ARDOUR::PresentationInfo::VCA) { - cmp_b = 1; + cmp_b = 2; } #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; + cmp_b = 1; } #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; } }; @@ -959,34 +995,59 @@ FaderPort8::assign_stripables (bool select_only) } } +/* **************************************************************************** + * Plugin selection and parameters + */ + void FaderPort8::assign_processor_ctrls () { - int n_parameters = _proc_params.size(); - if (n_parameters == 0) { + if (_proc_params.size() == 0) { _ctrls.set_fader_mode (ModeTrack); return; } set_periodic_display_mode (FP8Strip::PluginParam); + std::vector toggle_params; + std::vector slider_params; + + for ( std::list ::iterator i = _proc_params.begin(); i != _proc_params.end(); ++i) { + if ((*i).ac->toggled()) { + toggle_params.push_back (&(*i)); + } else { + slider_params.push_back (&(*i)); + } + } + + int n_parameters = std::max (toggle_params.size(), slider_params.size()); + _parameter_off = std::min (_parameter_off, n_parameters - 8); _parameter_off = std::max (0, _parameter_off); - int skip = _parameter_off; uint8_t id = 0; - for ( std::list ::iterator i = _proc_params.begin(); i != _proc_params.end(); ++i) { - if (skip > 0) { - --skip; - continue; + 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); + } + 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_TEXT0); - _ctrls.strip(id).set_fader_controllable ((*i).ac); - _ctrls.strip(id).set_text_line (0, (*i).name); + 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); + } + 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; } } + // clear remaining for (; id < 8; ++id) { _ctrls.strip(id).unset_controllables (); @@ -1001,8 +1062,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 ()); + PUSH_BACK_NON_NULL ("HP Freq", s->eq_hpf_controllable ()); + PUSH_BACK_NON_NULL ("LP Freq", s->eq_lpf_controllable ()); + 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->eq_hpf_controllable ()); +#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)); @@ -1011,7 +1081,7 @@ 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 ("Speed", s->comp_speed_controllable ()); PUSH_BACK_NON_NULL ("Mode", s->comp_mode_controllable ()); @@ -1110,12 +1180,16 @@ FaderPort8::spill_plugins () for (uint32_t i = 0; 0 != (proc = r->nth_plugin (i)); ++i) { if (!proc->display_to_user ()) { +#ifdef MIXBUS + boost::shared_ptr pi = boost::dynamic_pointer_cast (proc); + if (pi->is_channelstrip ()) // don't skip MB PRE +#endif continue; } 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 +1235,7 @@ FaderPort8::spill_plugins () break; } boost::shared_ptr pi = boost::dynamic_pointer_cast (proc); - boost::function cb (boost::bind (&FaderPort8::select_plugin, this, i)); + boost::function cb (boost::bind (&FaderPort8::select_plugin, this, procs[i])); _ctrls.strip(id).unset_controllables (FP8Strip::CTRL_ALL & ~FP8Strip::CTRL_TEXT & ~FP8Strip::CTRL_SELECT); _ctrls.strip(id).set_select_cb (cb); @@ -1213,6 +1287,10 @@ FaderPort8::spill_plugins () assert (id == 8); } +/* **************************************************************************** + * Aux Sends and Mixbus assigns + */ + void FaderPort8::assign_sends () { @@ -1255,7 +1333,6 @@ FaderPort8::assign_sends () _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)); - _ctrls.strip(id).set_solo_controllable (s->master_send_enable_controllable ()); // XXX if (++id == 8) { break; @@ -1265,17 +1342,18 @@ FaderPort8::assign_sends () for (; id < 8; ++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 ()); +#endif /* set select buttons */ + assigned_stripable_connections.drop_connections (); + _assigned_strips.clear (); 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) @@ -1284,15 +1362,15 @@ FaderPort8::assign_strips (bool reset_bank) _channel_off = 0; } - _assigned_strips.clear (); assigned_stripable_connections.drop_connections (); + _assigned_strips.clear (); FaderMode fadermode = _ctrls.fader_mode (); switch (fadermode) { 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) { @@ -1307,6 +1385,17 @@ FaderPort8::assign_strips (bool reset_bank) } } +/* **************************************************************************** + * some helper functions + */ + +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); + } +} void FaderPort8::drop_ctrl_connections () @@ -1316,6 +1405,46 @@ FaderPort8::drop_ctrl_connections () _showing_well_known = 0; } +/* 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); + stripable_selection_changed (); + } else { + ToggleStripableSelection (s); + } +#endif +} + +/* **************************************************************************** + * Assigned Stripable Callbacks + */ + void FaderPort8::notify_fader_mode_changed () { @@ -1346,10 +1475,6 @@ FaderPort8::notify_fader_mode_changed () notify_automation_mode_changed (); } -/* **************************************************************************** - * Assigned Stripable Callbacks - */ - void FaderPort8::notify_stripable_added_or_removed () { @@ -1363,30 +1488,6 @@ FaderPort8::notify_stripable_added_or_removed () 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 (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); - } -} - /* called from static PresentationInfo::Change */ void FaderPort8::notify_pi_property_changed (const PropertyChange& what_changed) @@ -1408,7 +1509,19 @@ FaderPort8::notify_stripable_property_changed (boost::weak_ptr ws, co assert (0); // this should not happen return; } - assert (_assigned_strips.find (s) != _assigned_strips.end()); + if (_assigned_strips.find (s) == _assigned_strips.end()) { + /* it can happen that signal emission is delayed. + * A signal may already be in the queue but the + * _assigned_strips has meanwhile changed. + * + * before _assigned_strips changes, the connections are dropped + * but that does not seem to invalidate pending requests :( + * + * Seen when creating a new MB session and Mixbusses are added + * incrementally. + */ + return; + } uint8_t id = _assigned_strips[s]; if (what_changed.contains (Properties::color)) { @@ -1418,10 +1531,11 @@ FaderPort8::notify_stripable_property_changed (boost::weak_ptr ws, co if (what_changed.contains (Properties::name)) { switch (_ctrls.fader_mode ()) { case ModeSend: - _ctrls.strip(id).set_text_line (0, s->name()); + _ctrls.strip(id).set_text_line (3, s->name(), true); + break; case ModeTrack: case ModePan: - _ctrls.strip(id).set_text_line (3, s->name(), true); + _ctrls.strip(id).set_text_line (0, s->name()); break; case ModePlugins: assert (0); @@ -1431,8 +1545,14 @@ FaderPort8::notify_stripable_property_changed (boost::weak_ptr ws, co } void -FaderPort8::gui_track_selection_changed (/*ARDOUR::StripableNotificationListPtr*/) +FaderPort8::stripable_selection_changed () { + if (!_device_active) { + /* this can be called anytime from the static + * ControlProtocol::StripableSelectionChanged + */ + return; + } automation_state_connections.drop_connections(); switch (_ctrls.fader_mode ()) { @@ -1574,7 +1694,6 @@ FaderPort8::bank_param (bool down, bool page) if (down) { dt *= -1; } - _channel_off += dt; switch (_ctrls.fader_mode ()) { case ModePlugins: if (_proc_params.size() > 0) { @@ -1586,6 +1705,7 @@ FaderPort8::bank_param (bool down, bool page) } break; case ModeSend: + _plugin_off += dt; assign_sends (); break; default: