Allow any one midi event to control only one thing.
authorLen Ovens <len@ovenwerks.net>
Mon, 20 Jul 2015 19:37:53 +0000 (12:37 -0700)
committerPaul Davis <paul@linuxaudiosystems.com>
Mon, 27 Jul 2015 20:17:38 +0000 (16:17 -0400)
libs/surfaces/generic_midi/generic_midi_control_protocol.cc
libs/surfaces/generic_midi/generic_midi_control_protocol.h
libs/surfaces/generic_midi/midicontrollable.cc

index 44d04e532d771dcff56851bdeaf6dafc8dddce28..8d1952d5f283e3ab981a274b6177ff30d0e7faf6 100644 (file)
@@ -299,6 +299,7 @@ GenericMidiControlProtocol::start_learning (Controllable* c)
        }
 
        Glib::Threads::Mutex::Lock lm2 (controllables_lock);
+       DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("Learn binding: Controlable number: %1\n", c));
 
        MIDIControllables::iterator tmp;
        for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) {
@@ -350,7 +351,6 @@ GenericMidiControlProtocol::start_learning (Controllable* c)
 
                pending_controllables.push_back (element);
        }
-
        mc->learn_about_external_control ();
        return true;
 }
@@ -425,6 +425,7 @@ GenericMidiControlProtocol::delete_binding (PBD::Controllable* control)
        }
 }
 
+// This next function seems unused
 void
 GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
 {
@@ -462,6 +463,65 @@ GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos,
        }
 }
 
+void
+GenericMidiControlProtocol::check_used_event (int pos, int control_number)
+{
+       Glib::Threads::Mutex::Lock lm2 (controllables_lock);
+
+       MIDI::channel_t channel = (pos & 0xf);
+       MIDI::byte value = control_number;
+
+       DEBUG_TRACE (DEBUG::GenericMidi, string_compose ("checking for used event: Channel: %1 Controller: %2 value: %3\n", (int) channel, (pos & 0xf0), (int) value));
+
+       // Remove any old binding for this midi channel/type/value pair
+       // Note:  can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
+       for (MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end();) {
+               MIDIControllable* existingBinding = (*iter);
+               if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
+                       if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
+                               DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
+                               delete existingBinding;
+                               iter = controllables.erase (iter);
+                       } else {
+                               ++iter;
+                       }
+               } else {
+                       ++iter;
+               }
+       }
+
+       for (MIDIFunctions::iterator iter = functions.begin(); iter != functions.end();) {
+               MIDIFunction* existingBinding = (*iter);
+               if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
+                       if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
+                               DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
+                               delete existingBinding;
+                               iter = functions.erase (iter);
+                       } else {
+                               ++iter;
+                       }
+               } else {
+                       ++iter;
+               }
+       }
+
+       for (MIDIActions::iterator iter = actions.begin(); iter != actions.end();) {
+               MIDIAction* existingBinding = (*iter);
+               if ( (existingBinding->get_control_type() & 0xf0 ) == (pos & 0xf0) && (existingBinding->get_control_channel() & 0xf ) == channel ) {
+                       if ( ((int) existingBinding->get_control_additional() == (int) value) || ((pos & 0xf0) == MIDI::pitchbend)) {
+                               DEBUG_TRACE (DEBUG::GenericMidi, "checking: found match, delete old binding.\n");
+                               delete existingBinding;
+                               iter = actions.erase (iter);
+                       } else {
+                               ++iter;
+                       }
+               } else {
+                       ++iter;
+               }
+       }
+
+}
+
 XMLNode&
 GenericMidiControlProtocol::get_state () 
 {
@@ -550,7 +610,6 @@ GenericMidiControlProtocol::set_state (const XMLNode& node, int version)
 
        {
                Glib::Threads::Mutex::Lock lm2 (controllables_lock);
-               controllables.clear ();
                nlist = node.children(); // "Controls"
 
                if (!nlist.empty()) {
index a4a51b7f99a5c2114894ee0aff282f15904cfafe..bb38a48401600011ce653a000665883990bbf74b 100644 (file)
@@ -71,6 +71,8 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
 
        int load_bindings (const std::string&);
        void drop_bindings ();
+
+       void check_used_event (int, int);
        
        std::string current_binding() const { return _current_binding; }
 
index f03a113cfe95654fd49b78061dd11a4cef43c2fb..81f2a5141da35759a80cf81fccc260c04608b4b9 100644 (file)
@@ -394,6 +394,7 @@ MIDIControllable::midi_receiver (Parser &, MIDI::byte *msg, size_t /*len*/)
                return;
        }
 
+       _surface->check_used_event(msg[0], msg[1]);
        bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]);
 
        if (controllable) {