LCXL: Add some Mixbus functionality
[ardour.git] / libs / surfaces / launch_control_xl / launch_control_xl.cc
index 2a4c8ce2d64e3ca1bbaa8aa72e1c13e630611717..f92d6125aae9a99ee3fe8dfb5937252cbfa2e1de 100644 (file)
@@ -29,9 +29,6 @@
 
 #include "midi++/parser.h"
 
-#include "temporal/time.h"
-#include "temporal/bbt_time.h"
-
 #include "ardour/amp.h"
 #include "ardour/async_midi_port.h"
 #include "ardour/audioengine.h"
@@ -84,9 +81,6 @@ LaunchControlXL::LaunchControlXL (ARDOUR::Session& s)
 
        /* master cannot be removed, so no need to connect to going-away signal */
        master = session->master_out ();
-       /* the master bus will always be on the last channel on the lcxl */
-       stripable[7] = master;
-
 
        run_event_loop ();
 
@@ -123,6 +117,7 @@ LaunchControlXL::~LaunchControlXL ()
        ports_release ();
 
        stop_event_loop ();
+       tear_down_gui ();
 }
 
 
@@ -149,11 +144,13 @@ LaunchControlXL::begin_using_device ()
 
        connect_session_signals ();
 
-
        init_buttons (true);
 
        in_use = true;
 
+       DEBUG_TRACE (DEBUG::LaunchControlXL, string_compose("use_fader8master inital value  '%1'\n", use_fader8master));
+       set_fader8master(use_fader8master);
+
        return 0;
 }
 
@@ -251,8 +248,10 @@ LaunchControlXL::bundles ()
 void
 LaunchControlXL::init_buttons (bool startup)
 {
+       reset(template_number());
+
        if (startup) {
-               button_track_mode(track_mode());
+               switch_bank(bank_start);
        }
 }
 
@@ -286,6 +285,13 @@ LaunchControlXL::do_request (LaunchControlRequest * req)
        }
 }
 
+void
+LaunchControlXL::reset(uint8_t chan)
+{
+       MidiByteArray msg (3, 176 + chan, 0, 0); // turn off all leds, reset buffer settings and duty cycle
+
+       write(msg);
+}
 int
 LaunchControlXL::set_active (bool yn)
 {
@@ -408,8 +414,7 @@ LaunchControlXL::handle_button_message(Button* button, MIDI::EventTwoBytes* ev)
                        NoteButton*     nb = id_note_button_map[*x];
                        if (cb != 0) {
                                cb->timeout_connection.disconnect();
-                       }
-                       else if (nb != 0) {
+                       } else if (nb != 0) {
                                        nb->timeout_connection.disconnect();
                        }
     }
@@ -417,8 +422,7 @@ LaunchControlXL::handle_button_message(Button* button, MIDI::EventTwoBytes* ev)
     buttons_down.insert(button->id());
     DEBUG_TRACE(DEBUG::LaunchControlXL, string_compose("button pressed: %1\n", LaunchControlXL::button_name_by_id(button->id())));
     start_press_timeout(button, button->id());
-  }
-  else {
+  } else {
     DEBUG_TRACE(DEBUG::LaunchControlXL, string_compose("button depressed: %1\n", LaunchControlXL::button_name_by_id(button->id())));
     buttons_down.erase(button->id());
     button->timeout_connection.disconnect();
@@ -429,17 +433,22 @@ LaunchControlXL::handle_button_message(Button* button, MIDI::EventTwoBytes* ev)
   if (c == consumed.end()) {
     if (ev->value == 0) {
       (this->*button->release_method)();
-    }
-    else {
+    } else {
       (this->*button->press_method)();
     }
-  }
-  else {
+  } else {
     DEBUG_TRACE(DEBUG::LaunchControlXL, "button was consumed, ignored\n");
     consumed.erase(c);
   }
 }
 
+bool
+LaunchControlXL::check_pick_up(Controller* controller, boost::shared_ptr<AutomationControl> ac)
+{
+       /* returns false until the controller value matches with the current setting of the stripable's ac */
+       return ( abs( controller->value() / 127.0 -  ac->internal_to_interface(ac->get_value()) ) < 0.007875 );
+}
+
 void
 LaunchControlXL::handle_knob_message (Knob* knob)
 {
@@ -450,17 +459,35 @@ LaunchControlXL::handle_knob_message (Knob* knob)
 
        boost::shared_ptr<AutomationControl> ac;
 
-       if (knob->id() < 8) { // sendA
-               ac = stripable[chan]->trim_control();
-       }
-       else if (knob->id() >= 8 && knob->id() < 16) { // sendB
-               ac = stripable[chan]->pan_width_control();
-       }
-       else if (knob->id() >= 16 && knob->id() < 24) { // pan
-               ac = stripable[chan]->pan_azimuth_control();
+       if (knob->id() < 8) { // sendA knob
+               if (buttons_down.find(Device) != buttons_down.end()) { // Device button hold
+                       ac = stripable[chan]->trim_control();
+               } else {
+                       ac = stripable[chan]->send_level_controllable (0);
+               }
+       } else if (knob->id() >= 8 && knob->id() < 16) { // sendB knob
+               if (buttons_down.find(Device) != buttons_down.end()) { // Device button hold
+#ifdef MIXBUS
+                       ac = stripable[chan]->filter_freq_controllable (true);
+#else
+                       /* something */
+#endif
+               } else {
+                       ac = stripable[chan]->send_level_controllable (1);
+               }
+       } else if (knob->id() >= 16 && knob->id() < 24) { // pan knob
+               if (buttons_down.find(Device) != buttons_down.end()) { // Device button hold
+#ifdef MIXBUS
+                       ac = stripable[chan]->comp_threshold_controllable();
+#else
+                       ac = stripable[chan]->pan_width_control();
+#endif
+               } else {
+                       ac = stripable[chan]->pan_azimuth_control();
+               }
        }
 
-       if (ac) {
+       if (ac && check_pick_up(knob, ac)) {
                ac->set_value ( ac->interface_to_internal( knob->value() / 127.0), PBD::Controllable::UseGroup );
        }
 }
@@ -474,7 +501,7 @@ LaunchControlXL::handle_fader_message (Fader* fader)
        }
 
        boost::shared_ptr<AutomationControl> ac = stripable[fader->id()]->gain_control();
-       if (ac) {
+       if (ac && check_pick_up(fader, ac)) {
                ac->set_value ( ac->interface_to_internal( fader->value() / 127.0), PBD::Controllable::UseGroup );
        }
 }
@@ -490,20 +517,18 @@ LaunchControlXL::handle_midi_controller_message (MIDI::Parser& parser, MIDI::Eve
        // DEBUG_TRACE (DEBUG::LaunchControlXL, string_compose ("CC %1 (value %2)\n", (int) ev->controller_number, (int) ev->value));
 
        CCControllerButtonMap::iterator b = cc_controller_button_map.find (ev->controller_number);
-       CCFaderMap::iterator f = cc_fader_map.find (ev->controller_number);
+       CCFaderMap::iterator f = cc_fader_map.find (ev->controller_number);
        CCKnobMap::iterator k = cc_knob_map.find (ev->controller_number);
 
        if (b != cc_controller_button_map.end()) {
                Button* button = b->second;
                handle_button_message(button, ev);
-       }
-       else if (f != cc_fader_map.end()) {
+       } else if (f != cc_fader_map.end()) {
                Fader* fader = f->second;
                fader->set_value(ev->value);
                handle_fader_message(fader);
 
-       }
-       else if (k != cc_knob_map.end()) {
+       } else if (k != cc_knob_map.end()) {
                Knob* knob = k->second;
                knob->set_value(ev->value);
                handle_knob_message(knob);
@@ -524,9 +549,9 @@ LaunchControlXL::handle_midi_note_on_message (MIDI::Parser& parser, MIDI::EventT
         NNNoteButtonMap::iterator b = nn_note_button_map.find (ev->controller_number);
 
         if (b != nn_note_button_map.end()) {
-               Button* button = b->second;
-               handle_button_message(button, ev);
-       }
+               Button* button = b->second;
+               handle_button_message(button, ev);
+       }
 }
 
 void LaunchControlXL::handle_midi_note_off_message(MIDI::Parser & parser, MIDI::EventTwoBytes *ev, MIDI::channel_t chan)
@@ -630,6 +655,10 @@ LaunchControlXL::get_state()
        child->add_child_nocopy (_async_out->get_state());
        node.add_child_nocopy (*child);
 
+       child = new XMLNode (X_("Configuration"));
+       child->set_property ("fader8master", LaunchControlXL::use_fader8master);
+       node.add_child_nocopy (*child);
+
        return node;
 }
 
@@ -660,6 +689,11 @@ LaunchControlXL::set_state (const XMLNode & node, int version)
                }
        }
 
+       if ((child = node.child (X_("Configuration"))) !=0) {
+               /* this should propably become a for-loop at some point */
+               child->get_property ("fader8master", use_fader8master);
+       }
+
        return retval;
 }
 
@@ -795,10 +829,10 @@ LaunchControlXL::stripable_property_change (PropertyChange const& what_changed,
                        return;
                }
                if (which < 8) {
-                       button_track_focus( (uint8_t)which );
+                       update_track_focus_led ((uint8_t) which);
+                       update_knob_led((uint8_t) which);
                }
        }
-
 }
 
 void
@@ -814,36 +848,38 @@ LaunchControlXL::switch_bank (uint32_t base)
        SelectButton* sl = static_cast<SelectButton*>(id_controller_button_map[SelectLeft]);
        SelectButton* sr = static_cast<SelectButton*>(id_controller_button_map[SelectRight]);
 
-       if (sl && sr) {
-               write(sl->state_msg( (base) ));
-               write(sr->state_msg( !(base) ));
-       }
-
-
-
-       stripable_connections.drop_connections ();
-
        /* work backwards so we can tell if we should actually switch banks */
 
        boost::shared_ptr<Stripable> s[8];
        uint32_t different = 0;
+       int stripable_counter;
+
+       if (LaunchControlXL::use_fader8master) {
+               stripable_counter = 7;
+       } else {
+               stripable_counter = 8;
+       }
 
-       for (int n = 0; n < 7; ++n) {
+       for (int n = 0; n < stripable_counter; ++n) {
                s[n] = session->get_remote_nth_stripable (base+n, PresentationInfo::Flag (PresentationInfo::Route|PresentationInfo::VCA));
                if (s[n] != stripable[n]) {
                        different++;
                }
        }
 
+       if (sl && sr) {
+               write(sl->state_msg((base)));
+               write(sr->state_msg((s[1] != 0)));
+       }
+
        if (!s[0]) {
                /* not even the first stripable exists, do nothing */
-               for (int n = 0; n < 7; ++n) {
-                       stripable[n].reset ();
-               }
                return;
        }
 
-       for (int n = 0; n < 7; ++n) {
+       stripable_connections.drop_connections ();
+
+       for (int n = 0; n < stripable_counter; ++n) {
                stripable[n] = s[n];
        }
 
@@ -863,11 +899,10 @@ LaunchControlXL::switch_bank (uint32_t base)
                        if (stripable[n]->rec_enable_control()) {
                                stripable[n]->rec_enable_control()->Changed.connect (stripable_connections, MISSING_INVALIDATOR, boost::bind (&LaunchControlXL::rec_changed, this, n), lcxl);
                        }
-
-
-                       button_track_focus(n);
-                       update_track_control_led(n);
                }
+               update_track_focus_led(n);
+               button_track_mode(track_mode());
+               update_knob_led(n);
        }
 }
 
@@ -898,3 +933,12 @@ void LaunchControlXL::set_track_mode (TrackMode mode) {
                break;
        }
 }
+
+void
+LaunchControlXL::set_fader8master (bool yn)
+{
+       if (yn) {
+               stripable[7] = master;
+       }
+       switch_bank(bank_start);
+}