X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fsurfaces%2Fgeneric_midi%2Fgeneric_midi_control_protocol.cc;h=cd8c724e75f5c1f6d22def36d79d659150613172;hb=4c90724d2d94f834ddc3c9b39c60dd7553493753;hp=8e8f707babf44aa135b82a3f8897c0e087e82e12;hpb=0d0f71ee92fb7ce53fbcb8c7b0cd93b1cdf3529f;p=ardour.git diff --git a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index 8e8f707bab..cd8c724e75 100644 --- a/libs/surfaces/generic_midi/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -15,9 +15,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ +#define __STDC_FORMAT_MACROS 1 +#include + #include #include @@ -25,7 +27,6 @@ #include #include -#include #include #include @@ -58,9 +59,17 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s) _feedback_interval = 10000; // microseconds last_feedback_time = 0; + auto_binding = FALSE; + Controllable::StartLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::start_learning)); Controllable::StopLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::stop_learning)); Session::SendFeedback.connect (mem_fun (*this, &GenericMidiControlProtocol::send_feedback)); + + Controllable::CreateBinding.connect (mem_fun (*this, &GenericMidiControlProtocol::create_binding)); + Controllable::DeleteBinding.connect (mem_fun (*this, &GenericMidiControlProtocol::delete_binding)); + + Session::AutoBindingOn.connect (mem_fun (*this, &GenericMidiControlProtocol::auto_binding_on)); + Session::AutoBindingOff.connect (mem_fun (*this, &GenericMidiControlProtocol::auto_binding_off)); } GenericMidiControlProtocol::~GenericMidiControlProtocol () @@ -115,8 +124,9 @@ GenericMidiControlProtocol::_send_feedback () if (end == buf) { return; } - - _port->write (buf, (int32_t) (end - buf)); + + // FIXME + //_port->write (buf, (int32_t) (end - buf)); } bool @@ -126,15 +136,51 @@ GenericMidiControlProtocol::start_learning (Controllable* c) return false; } - MIDIControllable* mc = new MIDIControllable (*_port, *c); + MIDIControllables::iterator tmp; + for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ) { + tmp = i; + ++tmp; + if (&(*i)->get_controllable() == c) { + delete (*i); + controllables.erase (i); + } + i = tmp; + } + + MIDIPendingControllables::iterator ptmp; + for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) { + ptmp = i; + ++ptmp; + if (&((*i).first)->get_controllable() == c) { + (*i).second.disconnect(); + delete (*i).first; + pending_controllables.erase (i); + } + i = ptmp; + } + + + MIDIControllable* mc = 0; + + for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) { + if ((*i)->get_controllable().id() == c->id()) { + mc = *i; + break; + } + } + + if (!mc) { + mc = new MIDIControllable (*_port, *c); + } { Glib::Mutex::Lock lm (pending_lock); - std::pair result; - result = pending_controllables.insert (mc); - if (result.second) { - c->LearningFinished.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc)); - } + + std::pair element; + element.first = mc; + element.second = c->LearningFinished.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc)); + + pending_controllables.push_back (element); } mc->learn_about_external_control (); @@ -147,10 +193,18 @@ GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc) Glib::Mutex::Lock lm (pending_lock); Glib::Mutex::Lock lm2 (controllables_lock); - MIDIControllables::iterator i = find (pending_controllables.begin(), pending_controllables.end(), mc); + MIDIPendingControllables::iterator tmp; + + for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ) { + tmp = i; + ++tmp; - if (i != pending_controllables.end()) { - pending_controllables.erase (i); + if ( (*i).first == mc) { + (*i).second.disconnect(); + pending_controllables.erase(i); + } + + i = tmp; } controllables.insert (mc); @@ -160,19 +214,92 @@ void GenericMidiControlProtocol::stop_learning (Controllable* c) { Glib::Mutex::Lock lm (pending_lock); + Glib::Mutex::Lock lm2 (controllables_lock); + MIDIControllable* dptr = 0; /* learning timed out, and we've been told to consider this attempt to learn to be cancelled. find the relevant MIDIControllable and remove it from the pending list. */ - for (MIDIControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) { - if (&(*i)->get_controllable() == c) { - (*i)->stop_learning (); - delete (*i); + for (MIDIPendingControllables::iterator i = pending_controllables.begin(); i != pending_controllables.end(); ++i) { + if (&((*i).first)->get_controllable() == c) { + (*i).first->stop_learning (); + dptr = (*i).first; + (*i).second.disconnect(); + pending_controllables.erase (i); break; } } + + if (dptr) { + delete dptr; + } +} + +void +GenericMidiControlProtocol::delete_binding ( PBD::Controllable* control ) +{ + if( control != 0 ) { + Glib::Mutex::Lock lm2 (controllables_lock); + + for( MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) { + MIDIControllable* existingBinding = (*iter); + + if( control == &(existingBinding->get_controllable()) ) { + delete existingBinding; + controllables.erase (iter); + } + + } // end for midi controllables + } // end null check +} +void +GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number) +{ + if( control != NULL ) { + Glib::Mutex::Lock lm2 (controllables_lock); + + MIDI::channel_t channel = (pos & 0xf); + MIDI::byte value = control_number; + + // Create a MIDIControllable:: + MIDIControllable* mc = new MIDIControllable (*_port, *control); + + // 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(); ++iter) { + MIDIControllable* existingBinding = (*iter); + + if( (existingBinding->get_control_channel() & 0xf ) == channel && + existingBinding->get_control_additional() == value && + (existingBinding->get_control_type() & 0xf0 ) == MIDI::controller ) { + + delete existingBinding; + controllables.erase (iter); + } + + } // end for midi controllables + + + // Update the MIDI Controllable based on the the pos param + // Here is where a table lookup for user mappings could go; for now we'll just wing it... + mc->bind_midi( channel, MIDI::controller, value ); + + controllables.insert (mc); + } // end null test +} + +void +GenericMidiControlProtocol::auto_binding_on() +{ + auto_binding = TRUE; +} + +void +GenericMidiControlProtocol::auto_binding_off() +{ + auto_binding = FALSE; } XMLNode& @@ -219,47 +346,47 @@ GenericMidiControlProtocol::set_state (const XMLNode& node) _feedback_interval = 10000; } - Controllable* c; - - { - Glib::Mutex::Lock lm (pending_lock); - pending_controllables.clear (); - } - - Glib::Mutex::Lock lm2 (controllables_lock); - - controllables.clear (); - - nlist = node.children(); - - if (nlist.empty()) { - return 0; - } - - nlist = nlist.front()->children (); - - for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - - if ((prop = (*niter)->property ("id")) != 0) { - - ID id = prop->value (); - - c = session->controllable_by_id (id); + // Are we using the autobinding feature? If so skip this part + if ( !auto_binding ) { + + boost::shared_ptr c; + + { + Glib::Mutex::Lock lm (pending_lock); + pending_controllables.clear (); + } + + Glib::Mutex::Lock lm2 (controllables_lock); + controllables.clear (); + nlist = node.children(); // "controls" + + if (nlist.empty()) { + return 0; + } + + nlist = nlist.front()->children (); + + for (niter = nlist.begin(); niter != nlist.end(); ++niter) { - if (c) { - MIDIControllable* mc = new MIDIControllable (*_port, *c); - if (mc->set_state (**niter) == 0) { - controllables.insert (mc); - } + if ((prop = (*niter)->property ("id")) != 0) { + + ID id = prop->value (); + c = session->controllable_by_id (id); - } else { - warning << string_compose (_("Generic MIDI control: controllable %1 not found in session (ignored)"), - id) - << endmsg; + if (c) { + MIDIControllable* mc = new MIDIControllable (*_port, *c); + if (mc->set_state (**niter) == 0) { + controllables.insert (mc); + } + + } else { + warning << string_compose (_("Generic MIDI control: controllable %1 not found in session (ignored)"), + id) + << endmsg; + } } } - } - + } // end autobinding check return 0; }