colinf's 2011-12-08 patch for freesound mootcher (add stop, remove URI, clear barberp...
[ardour.git] / libs / midi++2 / manager.cc
index ab37073afd59d9e2f4dafacb863b6689b9c0d6cd..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 ()
 {
-       PortMap::iterator i;
+       delete _mmc;
+       
+       /* This will delete our MTC etc. ports */
 
-       for (i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
-               delete (*i).second;
+       boost::shared_ptr<PortList> pr = _ports.reader ();
+       for (PortList::iterator p = pr->begin(); p != pr->end(); ++p) {
+               delete *p;
        }
 
-       ports_by_device.erase (ports_by_device.begin(), ports_by_device.end());
-       ports_by_tag.erase (ports_by_tag.begin(), ports_by_tag.end());
-
        if (theManager == this) {
                theManager = 0;
        }
 }
 
 Port *
-Manager::add_port (const XMLNode& node)
+Manager::add_port (Port* p)
 {
-       Port::Descriptor desc (node);
-       PortFactory factory;
-       Port *port;
-       PortMap::iterator existing;
-       pair<string, Port *> newpair;
-
-       if ((existing = ports_by_tag.find (desc.tag)) != ports_by_tag.end()) {
-
-               port = (*existing).second;
-               
-               if (port->mode() == desc.mode) {
-                       
-                       /* Same mode - reuse the port, and just
-                          create a new tag entry.
-                       */
-                       
-                       newpair.first = desc.tag;
-                       newpair.second = port;
-                       
-                       ports_by_tag.insert (newpair);
-                       return port;
-               }
-               
-               /* 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)) {
-                       error << "MIDIManager: port tagged \""
-                             << desc.tag
-                             << "\" cannot be opened duplex and non-duplex"
-                             << endmsg;
-                       return 0;
-               }
-               
-               /* modes must be different or complementary */
-       }
-
-       if (!PortFactory::ignore_duplicate_devices (desc.type)) {
-
-               if ((existing = ports_by_device.find (desc.device)) != ports_by_device.end()) {
-                       
-                       port = (*existing).second;
-                       
-                       if (port->mode() == desc.mode) {
-                               
-                               /* Same mode - reuse the port, and just
-                                  create a new tag entry.
-                               */
-                               
-                               newpair.first = desc.tag;
-                               newpair.second = port;
-                               
-                               ports_by_tag.insert (newpair);
-                               return port;
-                       }
-                       
-                       /* 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)) {
-                               error << "MIDIManager: port tagged \""
-                                     << desc.tag
-                                     << "\" cannot be opened duplex and non-duplex"
-                                     << endmsg;
-                               return 0;
-                       }
-                       
-                       /* modes must be different or complementary */
-               }
-       }
-       
-       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);
        }
 
-       newpair.first = port->name();
-       newpair.second = port;
-       ports_by_tag.insert (newpair);
-
-       newpair.first = port->device();
-       newpair.second = port;
-       ports_by_device.insert (newpair);
-
-       /* first port added becomes the default input
-          port.
-       */
-
-       if (inputPort == 0) {
-               inputPort = port;
-       } 
-
-       if (outputPort == 0) {
-               outputPort = port;
-       }
+       PortsChanged (); /* EMIT SIGNAL */
 
-       return port;
+       return p;
 }
 
-int 
-Manager::remove_port (Port* port)
+void
+Manager::remove_port (Port* p)
 {
-       PortMap::iterator res;
-
-       for (res = ports_by_device.begin(); res != ports_by_device.end(); ) {
-               PortMap::iterator tmp;
-               tmp = res;
-               ++tmp;
-               if (res->second == port) {
-                       ports_by_device.erase (res);
-               } 
-               res = tmp;
-       }
-
-
-       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); ) {
-               PortMap::iterator tmp;
-               tmp = res;
-               ++tmp;
-               if (res->second == port) {
-                       ports_by_tag.erase (res);
-               } 
-               res = tmp;
+       {
+               RCUWriter<PortList> writer (_ports);
+               boost::shared_ptr<PortList> pw = writer.get_copy ();
+               pw->remove (p);
        }
-       
-       delete port;
 
-       return 0;
+       PortsChanged (); /* EMIT SIGNAL */
 }
 
-int
-Manager::set_input_port (string tag)
+void
+Manager::cycle_start (pframes_t nframes)
 {
-       PortMap::iterator res;
-       bool found = false;
-
-       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
-               if (tag == (*res).first) {
-                       found = true;
-                       break;
-               }
-       }
+       boost::shared_ptr<PortList> pr = _ports.reader ();
        
-       if (!found) {
-               return -1;
+       for (PortList::iterator p = pr->begin(); p != pr->end(); ++p) {
+               (*p)->cycle_start (nframes);
        }
-
-       inputPort = (*res).second;
-
-       return 0;
 }
 
-int
-Manager::set_output_port (string tag)
-
+void
+Manager::cycle_end()
 {
-       PortMap::iterator res;
-       bool found = false;
-
-       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
-               if (tag == (*res).first) {
-                       found = true;
-                       break;
-               }
-       }
+       boost::shared_ptr<PortList> pr = _ports.reader ();
        
-       if (!found) {
-               return -1;
+       for (PortList::iterator p = pr->begin(); p != pr->end(); ++p) {
+               (*p)->cycle_end ();
        }
+}
 
-       // XXX send a signal to say we're about to change output ports
+/** Re-register ports that disappear on JACK shutdown */
+void
+Manager::reestablish (jack_client_t* jack)
+{
+       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 = (*res).second;
-
-       // 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 ()
 {
-       PortMap::iterator res;
+       boost::shared_ptr<PortList> pr = _ports.reader ();
 
-       for (res = ports_by_tag.begin(); res != ports_by_tag.end(); res++) {
-               if (name == (*res).first) {
-                       return (*res).second;
-               }
+       for (PortList::const_iterator p = pr->begin(); p != pr->end(); ++p) {
+               (*p)->reconnect ();
        }
-
-       return 0;
 }
 
-int
-Manager::foreach_port (int (*func)(const Port &, size_t, void *),
-                          void *arg)
+Port*
+Manager::port (string const & n)
 {
-       PortMap::const_iterator i;
-       int retval;
-       int n;
-               
-       for (n = 0, i = ports_by_device.begin(); 
-                   i != ports_by_device.end(); i++, n++) {
+       boost::shared_ptr<PortList> pr = _ports.reader ();
+       
+       PortList::const_iterator p = pr->begin();
+       while (p != pr->end() && (*p)->name() != n) {
+               ++p;
+       }
 
-               if ((retval = func (*((*i).second), 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 (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
-               (*i).second->cycle_start (nframes);
-       }
+       assert (theManager == 0);
+       theManager = new Manager (jack);
 }
 
 void
-Manager::cycle_end()
+Manager::set_port_states (list<XMLNode*> s)
 {
-       for (PortMap::iterator i = ports_by_device.begin(); i != ports_by_device.end(); i++) {
-               (*i).second->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;
 }