try not thinning when loading old-school automation lists
[ardour.git] / libs / ardour / audioengine.cc
index ea193ff6e287c908acf118e6b6704be3f41df960..7c3beb6c13d795bf8cd26a7b745e95c251766891 100644 (file)
 #include "pbd/unknown_type.h"
 #include "pbd/epa.h"
 
+#include <jack/weakjack.h>
+
 #include "midi++/port.h"
+#include "midi++/jack_midi_port.h"
 #include "midi++/mmc.h"
 #include "midi++/manager.h"
 
-#include "ardour/amp.h"
 #include "ardour/audio_port.h"
 #include "ardour/audioengine.h"
 #include "ardour/buffer.h"
-#include "ardour/buffer_set.h"
 #include "ardour/cycle_timer.h"
-#include "ardour/delivery.h"
-#include "ardour/event_type_map.h"
-#include "ardour/internal_return.h"
-#include "ardour/io.h"
+#include "ardour/internal_send.h"
 #include "ardour/meter.h"
 #include "ardour/midi_port.h"
-#include "ardour/process_thread.h"
 #include "ardour/port.h"
-#include "ardour/port_set.h"
+#include "ardour/process_thread.h"
 #include "ardour/session.h"
-#include "ardour/timestamps.h"
-#include "ardour/utils.h"
 
 #include "i18n.h"
 
@@ -82,6 +77,7 @@ AudioEngine::AudioEngine (string client_name, string session_uuid)
        _frame_rate = 0;
        _buffer_size = 0;
        _freewheeling = false;
+       _pre_freewheel_mmc_enabled = false;
         _main_thread = 0;
        port_remove_in_progress = false;
 
@@ -130,7 +126,7 @@ _thread_init_callback (void * /*arg*/)
 
        SessionEvent::create_per_thread_pool (X_("Audioengine"), 512);
 
-       MIDI::Port::set_process_thread (pthread_self());
+       MIDI::JackMIDIPort::set_process_thread (pthread_self());
 }
 
 static void
@@ -230,7 +226,7 @@ AudioEngine::stop (bool forever)
                } else {
                        jack_deactivate (_priv_jack);
                        Stopped(); /* EMIT SIGNAL */
-                       MIDI::Port::JackHalted (); /* EMIT SIGNAL */
+                       MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
                }
        }
 
@@ -314,13 +310,13 @@ AudioEngine::_xrun_callback (void *arg)
 void
 AudioEngine::_session_callback (jack_session_event_t *event, void *arg)
 {
-       printf( "helo.... " );
        AudioEngine* ae = static_cast<AudioEngine*> (arg);
        if (ae->connected()) {
                ae->JackSessionEvent ( event ); /* EMIT SIGNAL */
        }
 }
 #endif
+
 int
 AudioEngine::_graph_order_callback (void *arg)
 {
@@ -329,20 +325,10 @@ AudioEngine::_graph_order_callback (void *arg)
        if (ae->connected() && !ae->port_remove_in_progress) {
                ae->GraphReordered (); /* EMIT SIGNAL */
        }
+       
        return 0;
 }
 
-/** Wrapped which is called by JACK as its process callback.  It is just
- * here to get us back into C++ land by calling AudioEngine::process_callback()
- * @param nframes Number of frames passed by JACK.
- * @param arg User argument passed by JACK, which will be the AudioEngine*.
- */
-int
-AudioEngine::_process_callback (pframes_t nframes, void *arg)
-{
-       return static_cast<AudioEngine *> (arg)->process_callback (nframes);
-}
-
 void*
 AudioEngine::_process_thread (void *arg)
 {
@@ -352,7 +338,20 @@ AudioEngine::_process_thread (void *arg)
 void
 AudioEngine::_freewheel_callback (int onoff, void *arg)
 {
-       static_cast<AudioEngine*>(arg)->_freewheeling = onoff;
+       static_cast<AudioEngine*>(arg)->freewheel_callback (onoff);
+}
+
+void
+AudioEngine::freewheel_callback (int onoff)
+{
+       _freewheeling = onoff;
+
+       if (onoff) {
+               _pre_freewheel_mmc_enabled = MIDI::Manager::instance()->mmc()->send_enabled ();
+               MIDI::Manager::instance()->mmc()->enable_send (false);
+       } else {
+               MIDI::Manager::instance()->mmc()->enable_send (_pre_freewheel_mmc_enabled);
+       }
 }
 
 void
@@ -385,16 +384,16 @@ AudioEngine::_connect_callback (jack_port_id_t id_a, jack_port_id_t id_b, int co
        jack_port_t* jack_port_a = jack_port_by_id (_priv_jack, id_a);
        jack_port_t* jack_port_b = jack_port_by_id (_priv_jack, id_b);
 
-       Port* port_a = 0;
-       Port* port_b = 0;
+       boost::shared_ptr<Port> port_a;
+       boost::shared_ptr<Port> port_b;
 
        boost::shared_ptr<Ports> pr = ae->ports.reader ();
        Ports::iterator i = pr->begin ();
        while (i != pr->end() && (port_a == 0 || port_b == 0)) {
-               if (jack_port_a == (*i)->jack_port()) {
-                       port_a = *i;
-               } else if (jack_port_b == (*i)->jack_port()) {
-                       port_b = *i;
+               if (jack_port_a == i->second->jack_port()) {
+                       port_a = i->second;
+               } else if (jack_port_b == i->second->jack_port()) {
+                       port_b = i->second;
                }
                ++i;
        }
@@ -418,7 +417,7 @@ AudioEngine::split_cycle (pframes_t offset)
        boost::shared_ptr<Ports> p = ports.reader();
 
        for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-               (*i)->cycle_split ();
+               i->second->cycle_split ();
        }
 }
 
@@ -447,17 +446,18 @@ AudioEngine::process_thread ()
         return 0;
 }
 
-/** Method called by JACK (via _process_callback) which says that there
- * is work to be done.
- * @param nframes Number of frames to process.
+/** Method called by our ::process_thread when there is work to be done.
+ *  @param nframes Number of frames to process.
  */
 int
 AudioEngine::process_callback (pframes_t nframes)
 {
        GET_PRIVATE_JACK_POINTER_RET(_jack,0);
-       // CycleTimer ct ("AudioEngine::process");
        Glib::Mutex::Lock tm (_process_lock, Glib::TRY_LOCK);
 
+       PT_TIMING_REF;
+       PT_TIMING_CHECK (1);
+
        /// The number of frames that will have been processed when we've finished
        pframes_t next_processed_frames;
 
@@ -469,12 +469,21 @@ AudioEngine::process_callback (pframes_t nframes)
                next_processed_frames = _processed_frames + nframes;
        }
 
-       if (!tm.locked() || _session == 0) {
+       if (!tm.locked()) {
                /* return having done nothing */
                _processed_frames = next_processed_frames;
                return 0;
        }
 
+       if (_session == 0) {
+               if (!_freewheeling) {
+                       MIDI::Manager::instance()->cycle_start(nframes);
+                       MIDI::Manager::instance()->cycle_end();
+               }
+               _processed_frames = next_processed_frames;
+               return 0;
+       }
+
        if (session_remove_pending) {
                /* perform the actual session removal */
                _session = 0;
@@ -486,17 +495,16 @@ AudioEngine::process_callback (pframes_t nframes)
 
        /* tell all relevant objects that we're starting a new cycle */
 
-       Delivery::CycleStart (nframes);
+       InternalSend::CycleStart (nframes);
        Port::set_global_port_buffer_offset (0);
         Port::set_cycle_framecnt (nframes);
-       InternalReturn::CycleStart (nframes);
 
        /* tell all Ports that we're starting a new cycle */
 
        boost::shared_ptr<Ports> p = ports.reader();
 
        for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-               (*i)->cycle_start (nframes);
+               i->second->cycle_start (nframes);
        }
 
        /* test if we are freewheeling and there are freewheel signals connected.
@@ -512,10 +520,13 @@ AudioEngine::process_callback (pframes_t nframes)
                }
 
        } else {
+               MIDI::Manager::instance()->cycle_start(nframes);
+
                if (_session) {
                        _session->process (nframes);
-
                }
+
+               MIDI::Manager::instance()->cycle_end();
        }
 
        if (_freewheeling) {
@@ -533,15 +544,14 @@ AudioEngine::process_callback (pframes_t nframes)
 
                for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
 
-                       Port *port = (*i);
                        bool x;
 
-                       if (port->last_monitor() != (x = port->monitoring_input ())) {
-                               port->set_last_monitor (x);
+                       if (i->second->last_monitor() != (x = i->second->jack_monitoring_input ())) {
+                               i->second->set_last_monitor (x);
                                /* XXX I think this is dangerous, due to
                                   a likely mutex in the signal handlers ...
                                */
-                                port->MonitorInputChanged (x); /* EMIT SIGNAL */
+                               i->second->MonitorInputChanged (x); /* EMIT SIGNAL */
                        }
                }
                last_monitor_check = next_processed_frames;
@@ -553,10 +563,8 @@ AudioEngine::process_callback (pframes_t nframes)
 
                for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
 
-                       Port *port = (*i);
-
-                       if (port->sends_output()) {
-                               port->get_buffer(nframes).silence(nframes);
+                       if (i->second->sends_output()) {
+                               i->second->get_buffer(nframes).silence(nframes);
                        }
                }
        }
@@ -564,10 +572,13 @@ AudioEngine::process_callback (pframes_t nframes)
        // Finalize ports
 
        for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-               (*i)->cycle_end (nframes);
+               i->second->cycle_end (nframes);
        }
 
        _processed_frames = next_processed_frames;
+
+       PT_TIMING_CHECK (2);
+       
        return 0;
 }
 
@@ -652,7 +663,7 @@ AudioEngine::jack_bufsize_callback (pframes_t nframes)
                boost::shared_ptr<Ports> p = ports.reader();
 
                for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-                       (*i)->reset();
+                       i->second->reset();
                }
        }
 
@@ -717,7 +728,7 @@ AudioEngine::set_session (Session *s)
                boost::shared_ptr<Ports> p = ports.reader();
 
                for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-                       (*i)->cycle_start (blocksize);
+                       i->second->cycle_start (blocksize);
                }
 
                _session->process (blocksize);
@@ -730,7 +741,7 @@ AudioEngine::set_session (Session *s)
                _session->process (blocksize);
 
                for (Ports::iterator i = p->begin(); i != p->end(); ++i) {
-                       (*i)->cycle_end (blocksize);
+                       i->second->cycle_end (blocksize);
                }
        }
 }
@@ -771,29 +782,29 @@ AudioEngine::port_registration_failure (const std::string& portname)
        if (p) {
                reason = string_compose (_("a port with the name \"%1\" already exists: check for duplicated track/bus names"), portname);
        } else {
-               reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with ports if you need this many tracks."), PROGRAM_NAME);
+               reason = string_compose (_("No more JACK ports are available. You will need to stop %1 and restart JACK with more ports if you need this many tracks."), PROGRAM_NAME);
        }
 
        throw PortRegistrationFailure (string_compose (_("AudioEngine: cannot register port \"%1\": %2"), portname, reason).c_str());
 }
 
-Port*
+boost::shared_ptr<Port>
 AudioEngine::register_port (DataType dtype, const string& portname, bool input)
 {
-       Port* newport;
+       boost::shared_ptr<Port> newport;
 
        try {
                if (dtype == DataType::AUDIO) {
-                       newport = new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput));
+                       newport.reset (new AudioPort (portname, (input ? Port::IsInput : Port::IsOutput)));
                } else if (dtype == DataType::MIDI) {
-                       newport = new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput));
+                       newport.reset (new MidiPort (portname, (input ? Port::IsInput : Port::IsOutput)));
                } else {
                        throw PortRegistrationFailure("unable to create port (unknown type)");
                }
 
                RCUWriter<Ports> writer (ports);
                boost::shared_ptr<Ports> ps = writer.get_copy ();
-               ps->insert (ps->begin(), newport);
+               ps->insert (make_pair (make_port_name_relative (portname), newport));
 
                /* writer goes out of scope, forces update */
 
@@ -810,20 +821,20 @@ AudioEngine::register_port (DataType dtype, const string& portname, bool input)
        }
 }
 
-Port *
+boost::shared_ptr<Port>
 AudioEngine::register_input_port (DataType type, const string& portname)
 {
        return register_port (type, portname, true);
 }
 
-Port *
+boost::shared_ptr<Port>
 AudioEngine::register_output_port (DataType type, const string& portname)
 {
        return register_port (type, portname, false);
 }
 
 int
-AudioEngine::unregister_port (Port& port)
+AudioEngine::unregister_port (boost::shared_ptr<Port> port)
 {
        /* caller must hold process lock */
 
@@ -837,18 +848,17 @@ AudioEngine::unregister_port (Port& port)
        {
                RCUWriter<Ports> writer (ports);
                boost::shared_ptr<Ports> ps = writer.get_copy ();
+               Ports::iterator x = ps->find (make_port_name_relative (port->name()));
 
-               for (Ports::iterator i = ps->begin(); i != ps->end(); ++i) {
-                       if ((*i) == &port) {
-                               delete *i;
-                               ps->erase (i);
-                               break;
-                       }
+               if (x != ps->end()) {
+                       ps->erase (x);
                }
 
                /* writer goes out of scope, forces update */
        }
 
+       ports.flush ();
+
        return 0;
 }
 
@@ -870,8 +880,8 @@ AudioEngine::connect (const string& source, const string& destination)
        string d = make_port_name_non_relative (destination);
 
 
-       Port* src = get_port_by_name (s);
-       Port* dst = get_port_by_name (d);
+       boost::shared_ptr<Port> src = get_port_by_name (s);
+       boost::shared_ptr<Port> dst = get_port_by_name (d);
 
        if (src) {
                ret = src->connect (d);
@@ -910,8 +920,8 @@ AudioEngine::disconnect (const string& source, const string& destination)
        string s = make_port_name_non_relative (source);
        string d = make_port_name_non_relative (destination);
 
-       Port* src = get_port_by_name (s);
-       Port* dst = get_port_by_name (d);
+       boost::shared_ptr<Port> src = get_port_by_name (s);
+       boost::shared_ptr<Port> dst = get_port_by_name (d);
 
        if (src) {
                        ret = src->disconnect (d);
@@ -925,7 +935,7 @@ AudioEngine::disconnect (const string& source, const string& destination)
 }
 
 int
-AudioEngine::disconnect (Port& port)
+AudioEngine::disconnect (boost::shared_ptr<Port> port)
 {
        GET_PRIVATE_JACK_POINTER_RET (_jack,-1);
 
@@ -938,7 +948,7 @@ AudioEngine::disconnect (Port& port)
                }
        }
 
-       return port.disconnect_all ();
+       return port->disconnect_all ();
 }
 
 ARDOUR::framecnt_t
@@ -971,10 +981,10 @@ AudioEngine::frames_per_cycle () const
 }
 
 /** @param name Full or short name of port
- *  @return Corresponding Port* or 0. This object remains the property of the AudioEngine
- *  so must not be deleted.
+ *  @return Corresponding Port or 0.
  */
-Port*
+
+boost::shared_ptr<Port>
 AudioEngine::get_port_by_name (const string& portname)
 {
        if (!_running) {
@@ -982,26 +992,47 @@ AudioEngine::get_port_by_name (const string& portname)
                        fatal << _("get_port_by_name() called before engine was started") << endmsg;
                        /*NOTREACHED*/
                } else {
-                       return 0;
+                       boost::shared_ptr<Port> ();
                }
        }
 
         if (!port_is_mine (portname)) {
                 /* not an ardour port */
-                return 0;
+                return boost::shared_ptr<Port> ();
         }
 
-       std::string const rel = make_port_name_relative (portname);
-
        boost::shared_ptr<Ports> pr = ports.reader();
-
-       for (Ports::iterator i = pr->begin(); i != pr->end(); ++i) {
-               if (rel == (*i)->name()) {
-                       return *i;
+       std::string rel = make_port_name_relative (portname);
+       Ports::iterator x = pr->find (rel);
+
+       if (x != pr->end()) {
+               /* its possible that the port was renamed by some 3rd party and
+                  we don't know about it. check for this (the check is quick
+                  and cheap), and if so, rename the port (which will alter
+                  the port map as a side effect).
+               */
+               const std::string check = make_port_name_relative (jack_port_name (x->second->jack_port()));
+               if (check != rel) {
+                       x->second->set_name (check);
                }
+               return x->second;
        }
 
-        return 0;
+        return boost::shared_ptr<Port> ();
+}
+
+void
+AudioEngine::port_renamed (const std::string& old_relative_name, const std::string& new_relative_name)
+{
+       RCUWriter<Ports> writer (ports);
+       boost::shared_ptr<Ports> p = writer.get_copy();
+       Ports::iterator x = p->find (old_relative_name);
+       
+       if (x != p->end()) {
+               boost::shared_ptr<Port> port = x->second;
+               p->erase (x);
+               p->insert (make_pair (new_relative_name, port));
+       }
 }
 
 const char **
@@ -1068,7 +1099,7 @@ AudioEngine::halted (void *arg)
 
        if (was_running) {
                ae->Halted(""); /* EMIT SIGNAL */
-               MIDI::Port::JackHalted (); /* EMIT SIGNAL */
+               MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
        }
 }
 
@@ -1244,14 +1275,9 @@ AudioEngine::remove_all_ports ()
        /* process lock MUST be held by caller
        */
 
-       vector<Port*> to_be_deleted;
-
        {
                RCUWriter<Ports> writer (ports);
                boost::shared_ptr<Ports> ps = writer.get_copy ();
-               for (Ports::iterator i = ps->begin(); i != ps->end(); ++i) {
-                       to_be_deleted.push_back (*i);
-               }
                ps->clear ();
        }
 
@@ -1259,14 +1285,6 @@ AudioEngine::remove_all_ports ()
 
        ports.flush ();
 
-       /* now do the actual deletion, given that "ports" is now empty, thus
-          preventing anyone else from getting a handle on a Port
-       */
-
-       for (vector<Port*>::iterator p = to_be_deleted.begin(); p != to_be_deleted.end(); ++p) {
-               delete *p;
-       }
-
        port_remove_in_progress = false;
 }
 
@@ -1331,7 +1349,7 @@ AudioEngine::disconnect_from_jack ()
        if (_running) {
                _running = false;
                Stopped(); /* EMIT SIGNAL */
-               MIDI::Port::JackHalted (); /* EMIT SIGNAL */
+               MIDI::JackMIDIPort::JackHalted (); /* EMIT SIGNAL */
        }
 
        return 0;
@@ -1356,7 +1374,7 @@ AudioEngine::reconnect_to_jack ()
        boost::shared_ptr<Ports> p = ports.reader ();
 
        for (i = p->begin(); i != p->end(); ++i) {
-               if ((*i)->reestablish ()) {
+               if (i->second->reestablish ()) {
                        break;
                }
        }
@@ -1391,7 +1409,7 @@ AudioEngine::reconnect_to_jack ()
        /* re-establish connections */
 
        for (i = p->begin(); i != p->end(); ++i) {
-               (*i)->reconnect ();
+               i->second->reconnect ();
        }
 
        MIDI::Manager::instance()->reconnect ();
@@ -1511,7 +1529,7 @@ AudioEngine::port_is_physical (const std::string& portname) const
 }
 
 void
-AudioEngine::ensure_monitor_input (const std::string& portname, bool yn) const
+AudioEngine::request_jack_monitors_input (const std::string& portname, bool yn) const
 {
         GET_PRIVATE_JACK_POINTER(_jack);
 
@@ -1532,3 +1550,10 @@ AudioEngine::update_latencies ()
                 jack_recompute_total_latencies (_priv_jack);
         }
 }
+
+void
+AudioEngine::destroy ()
+{
+       delete _instance;
+       _instance = 0;
+}