colinf's 2011-12-08 patch for freesound mootcher (add stop, remove URI, clear barberp...
[ardour.git] / libs / midi++2 / manager.cc
index 7cd03a6311d03a12870f5eb5ea46bb60c8ee4559..61d4c4c363ba31ac25c5f9fa8198af6058eb9ad4 100644 (file)
 
 #include "midi++/types.h"
 #include "midi++/manager.h"
-#include "midi++/factory.h"
 #include "midi++/channel.h"
+#include "midi++/port.h"
+#include "midi++/mmc.h"
 
 using namespace std;
 using namespace MIDI;
 using namespace PBD;
 
-/* XXX check for strdup leaks */
-
 Manager *Manager::theManager = 0;
 
-Manager::Manager () 
+Manager::Manager (jack_client_t* jack)
+       : _ports (new PortList)
 {
-       inputPort = 0;
-       outputPort = 0;
-       inputChannelNumber = 0;
-       outputChannelNumber = 0;
-       api_data = 0;
+       _mmc = new MachineControl (this, jack);
+       
+       _mtc_input_port = add_port (new MIDI::Port ("MTC in", Port::IsInput, jack));
+       _mtc_output_port = add_port (new MIDI::Port ("MTC out", Port::IsOutput, jack));
+       _midi_input_port = add_port (new MIDI::Port ("MIDI control in", Port::IsInput, jack));
+       _midi_output_port = add_port (new MIDI::Port ("MIDI control out", Port::IsOutput, jack));
+       _midi_clock_input_port = add_port (new MIDI::Port ("MIDI clock in", Port::IsInput, jack));
+       _midi_clock_output_port = add_port (new MIDI::Port ("MIDI clock out", Port::IsOutput, jack));
 }
 
 Manager::~Manager ()
 {
-       for (PortList::iterator p = _ports.begin(); p != _ports.end(); ++p) {
+       delete _mmc;
+       
+       /* This will delete our MTC etc. ports */
+
+       boost::shared_ptr<PortList> pr = _ports.reader ();
+       for (PortList::iterator p = pr->begin(); p != pr->end(); ++p) {
                delete *p;
        }
 
@@ -57,173 +65,112 @@ Manager::~Manager ()
 }
 
 Port *
-Manager::add_port (const XMLNode& node)
+Manager::add_port (Port* p)
 {
-       Port::Descriptor desc (node);
-       PortFactory factory;
-       Port *port;
-       PortList::iterator p;
-
-       for (p = _ports.begin(); p != _ports.end(); ++p) {
-
-               if (desc.tag == (*p)->name()) {
-                       break;
-               } 
-
-               if (!PortFactory::ignore_duplicate_devices (desc.type)) {
-                       if (desc.device == (*p)->device()) {
-                               /* If the existing is duplex, and this request
-                                  is not, then fail, because most drivers won't
-                                  allow opening twice with duplex and non-duplex
-                                  operation.
-                               */
-
-                               if ((desc.mode == O_RDWR && port->mode() != O_RDWR) ||
-                                   (desc.mode != O_RDWR && port->mode() == O_RDWR)) {
-                                       break;
-                               }
-                       }
-               }
-       }
-
-       if (p != _ports.end()) {
-               return 0;
-       }
-       
-       port = factory.create_port (node, api_data);
-       
-       if (port == 0) {
-               return 0;
-       }
-
-       if (!port->ok()) {
-               delete port;
-               return 0;
+       {
+               RCUWriter<PortList> writer (_ports);
+               boost::shared_ptr<PortList> pw = writer.get_copy ();
+               pw->push_back (p);
        }
 
-       _ports.push_back (port);
+       PortsChanged (); /* EMIT SIGNAL */
 
-       /* first port added becomes the default input
-          port.
-       */
-
-       if (inputPort == 0) {
-               inputPort = port;
-       } 
+       return p;
+}
 
-       if (outputPort == 0) {
-               outputPort = port;
+void
+Manager::remove_port (Port* p)
+{
+       {
+               RCUWriter<PortList> writer (_ports);
+               boost::shared_ptr<PortList> pw = writer.get_copy ();
+               pw->remove (p);
        }
 
-       return port;
+       PortsChanged (); /* EMIT SIGNAL */
 }
 
-int 
-Manager::remove_port (Port* port)
+void
+Manager::cycle_start (pframes_t nframes)
 {
-       if (inputPort == port) {
-               inputPort = 0;
-       }
-       if (outputPort == port) {
-               outputPort = 0;
+       boost::shared_ptr<PortList> pr = _ports.reader ();
+       
+       for (PortList::iterator p = pr->begin(); p != pr->end(); ++p) {
+               (*p)->cycle_start (nframes);
        }
-       _ports.remove (port);
-       delete port;
-       return 0;
 }
 
-int
-Manager::set_input_port (string tag)
+void
+Manager::cycle_end()
 {
-       for (PortList::iterator p = _ports.begin(); p != _ports.end(); ++p) {
-               if ((*p)->name() == tag) {
-                       inputPort = (*p);
-                       return 0;
-               }
+       boost::shared_ptr<PortList> pr = _ports.reader ();
+       
+       for (PortList::iterator p = pr->begin(); p != pr->end(); ++p) {
+               (*p)->cycle_end ();
        }
-
-       return -1;
 }
 
-int
-Manager::set_output_port (string tag)
+/** Re-register ports that disappear on JACK shutdown */
+void
+Manager::reestablish (jack_client_t* jack)
 {
-       PortList::iterator p;
-
-       for (p = _ports.begin(); p != _ports.end(); ++p) {
-               if ((*p)->name() == tag) {
-                       inputPort = (*p);
-                       break;
-               }
-       }
-
-       if (p == _ports.end()) {
-               return -1;
-       }
-
-       // XXX send a signal to say we're about to change output ports
+       boost::shared_ptr<PortList> pr = _ports.reader ();
 
-       if (outputPort) {
-               for (channel_t chan = 0; chan < 16; chan++) {
-                       outputPort->channel (chan)->all_notes_off (0);
-               }
+       for (PortList::const_iterator p = pr->begin(); p != pr->end(); ++p) {
+               (*p)->reestablish (jack);
        }
-       
-       outputPort = (*p);
-
-       // XXX send a signal to say we've changed output ports
-
-       return 0;
 }
 
-Port *
-Manager::port (string name)
+/** Re-connect ports after a reestablish () */
+void
+Manager::reconnect ()
 {
-       for (PortList::iterator p = _ports.begin(); p != _ports.end(); ++p) {
-               if (name == (*p)->name()) {
-                       return (*p);
-               }
-       }
+       boost::shared_ptr<PortList> pr = _ports.reader ();
 
-       return 0;
+       for (PortList::const_iterator p = pr->begin(); p != pr->end(); ++p) {
+               (*p)->reconnect ();
+       }
 }
 
-int
-Manager::foreach_port (int (*func)(const Port &, size_t, void *),
-                          void *arg)
+Port*
+Manager::port (string const & n)
 {
-       int n = 0;
-               
-       for (PortList::const_iterator p = _ports.begin(); p != _ports.end(); ++p, ++n) {
-               int retval;
+       boost::shared_ptr<PortList> pr = _ports.reader ();
+       
+       PortList::const_iterator p = pr->begin();
+       while (p != pr->end() && (*p)->name() != n) {
+               ++p;
+       }
 
-               if ((retval = func (**p, n, arg)) != 0) {
-                       return retval;
-               }
+       if (p == pr->end()) {
+               return 0;
        }
 
-       return 0;
+       return *p;
 }
 
 void
-Manager::cycle_start(nframes_t nframes)
+Manager::create (jack_client_t* jack)
 {
-       for (PortList::iterator p = _ports.begin(); p != _ports.end(); ++p) {
-               (*p)->cycle_start (nframes);
-       }
+       assert (theManager == 0);
+       theManager = new Manager (jack);
 }
 
 void
-Manager::cycle_end()
+Manager::set_port_states (list<XMLNode*> s)
 {
-       for (PortList::iterator p = _ports.begin(); p != _ports.end(); ++p) {
-               (*p)->cycle_end ();
+       boost::shared_ptr<PortList> pr = _ports.reader ();
+       
+       for (list<XMLNode*>::iterator i = s.begin(); i != s.end(); ++i) {
+               for (PortList::const_iterator j = pr->begin(); j != pr->end(); ++j) {
+                       (*j)->set_state (**i);
+               }
        }
 }
 
-
-int
-Manager::get_known_ports (vector<PortSet>& ports)
+void
+Manager::destroy ()
 {
-       return PortFactory::get_known_ports (ports);
+       delete theManager;
+       theManager = 0;
 }