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));
}
FaderPort8::~FaderPort8 ()
{
cerr << "~FP8\n";
- stop_midi_handling ();
+ disconnected ();
close ();
if (_input_port) {
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 ();
}
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.
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<ARDOUR::Port>, std::string name1, boost::weak_ptr<ARDOUR::Port>, 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");
string no = ARDOUR::AudioEngine::instance()->make_port_name_non_relative (boost::shared_ptr<ARDOUR::Port>(_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;
} 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;
}
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);
}
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);
}
}
struct FP8SortByNewDisplayOrder
{
- // return (a < b)
+ // return strict (a < b)
bool operator () (const boost::shared_ptr<Stripable> & a, const boost::shared_ptr<Stripable> & b) const
{
if (a->presentation_info().flags () == b->presentation_info().flags ()) {
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;
}
};
}
}
+/* ****************************************************************************
+ * Plugin selection and parameters
+ */
+
void
FaderPort8::assign_processor_ctrls ()
{
_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));
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 ());
for (uint32_t i = 0; 0 != (proc = r->nth_plugin (i)); ++i) {
if (!proc->display_to_user ()) {
+#ifdef MIXBUS
+ boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (proc);
+ if (pi->is_channelstrip ()) // don't skip MB PRE
+#endif
continue;
}
int n_controls = 0;
set<Evoral::Parameter> p = proc->what_can_be_automated ();
- for (set<Evoral::Parameter>::iterator i = p.begin(); i != p.end(); ++i) {
- std::string n = proc->describe_parameter (*i);
+ for (set<Evoral::Parameter>::iterator j = p.begin(); j != p.end(); ++j) {
+ std::string n = proc->describe_parameter (*j);
if (n == "hidden") {
continue;
}
break;
}
boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (proc);
- boost::function<void ()> cb (boost::bind (&FaderPort8::select_plugin, this, i));
+ boost::function<void ()> 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);
assert (id == 8);
}
+/* ****************************************************************************
+ * Aux Sends and Mixbus assigns
+ */
+
void
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;
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)
_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) {
}
}
+/* ****************************************************************************
+ * 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 ()
_showing_well_known = 0;
}
+/* functor for FP8Strip's select button */
+void
+FaderPort8::select_strip (boost::weak_ptr<Stripable> ws)
+{
+ boost::shared_ptr<Stripable> 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 ()
{
notify_automation_mode_changed ();
}
-/* ****************************************************************************
- * Assigned Stripable Callbacks
- */
-
void
FaderPort8::notify_stripable_added_or_removed ()
{
assign_strips (false);
}
-/* functor for FP8Strip's select button */
-void
-FaderPort8::select_strip (boost::weak_ptr<Stripable> ws)
-{
- boost::shared_ptr<Stripable> 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)
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)) {
}
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 ()) {
if (down) {
dt *= -1;
}
- _channel_off += dt;
switch (_ctrls.fader_mode ()) {
case ModePlugins:
if (_proc_params.size() > 0) {
}
break;
case ModeSend:
+ _plugin_off += dt;
assign_sends ();
break;
default: