Make DnD copy processors using their XML representations. Remove unused
[ardour.git] / libs / ardour / route.cc
index 78d4a85e61e99e1523d85f19ab8bbdfc86924d93..21b7876aca4e0da309a58c2fe052aa40651d3b69 100644 (file)
@@ -25,6 +25,7 @@
 #include <pbd/xml++.h>
 #include <pbd/enumwriter.h>
 #include <pbd/stacktrace.h>
+#include <pbd/memento_command.h>
 
 #include <ardour/timestamps.h>
 #include <ardour/audioengine.h>
@@ -57,7 +58,7 @@ using namespace ARDOUR;
 using namespace PBD;
 
 uint32_t Route::order_key_cnt = 0;
-sigc::signal<void> Route::SyncOrderKeys;
+sigc::signal<void,const char*> Route::SyncOrderKeys;
 
 Route::Route (Session& sess, string name, int input_min, int input_max, int output_min, int output_max, Flag flg, DataType default_type)
        : IO (sess, name, input_min, input_max, output_min, output_max, default_type),
@@ -128,9 +129,7 @@ Route::~Route ()
                free ((void*)(i->first));
        }
 
-       if (_control_outs) {
-               delete _control_outs;
-       }
+       delete _control_outs;
 }
 
 void
@@ -177,20 +176,32 @@ Route::set_order_key (const char* name, long n)
 }
 
 void
-Route::sync_order_keys ()
+Route::sync_order_keys (const char* base)
 {
-       uint32_t key;
-       
        if (order_keys.empty()) {
                return;
        }
-       
-       OrderKeys::iterator x = order_keys.begin();
-       key = x->second;
-       ++x;
 
-       for (; x != order_keys.end(); ++x) {
-               x->second = key;
+       OrderKeys::iterator i;
+       uint32_t key;
+
+       if ((i = order_keys.find (base)) == order_keys.end()) {
+               /* key doesn't exist, use the first existing
+                  key (this is done during session initialization)
+               */
+               i = order_keys.begin();
+               key = i->second;
+               ++i;
+       } else {
+               /* key exists - use it and reset all others
+                  (actually, itself included)
+               */
+               i = order_keys.begin();
+               key = i->second;
+       }
+
+       for (; i != order_keys.end(); ++i) {
+               i->second = key;
        }
 }
 
@@ -447,8 +458,12 @@ Route::process_output_buffers (BufferSet& bufs,
                } 
        }
 
-       // This really should already be true...
-       bufs.set_count(pre_fader_streams());
+       /* When we entered this method, the number of bufs was set by n_process_buffers(), so
+        * it may be larger than required.  Consider, for example, a mono track with two redirects A and B.
+        * If A has one input and three outputs, and B three inputs and one output, n_process_buffers()
+        * will be 3.  In this case, now we've done pre-fader redirects, we can reset the number of bufs.
+        */
+       bufs.set_count (pre_fader_streams());
        
        if (!_soloed && (mute_gain != dmg) && !mute_declick_applied && _mute_affects_post_fader) {
                Amp::run_in_place (bufs, nframes, mute_gain, dmg, false);
@@ -1075,6 +1090,31 @@ Route::set_solo (bool yn, void *src)
                _soloed = yn;
                solo_changed (src); /* EMIT SIGNAL */
                _solo_control->Changed (); /* EMIT SIGNAL */
+       }       
+       
+       catch_up_on_solo_mute_override ();
+}
+
+void
+Route::catch_up_on_solo_mute_override ()
+{
+       if (Config->get_solo_model() != InverseMute) {
+               return;
+       }
+       
+       {
+
+               Glib::Mutex::Lock lm (declick_lock);
+               
+               if (_muted) {
+                       if (Config->get_solo_mute_override()) {
+                               desired_mute_gain = (_soloed?1.0:0.0);
+                       } else {
+                               desired_mute_gain = 0.0;
+                       }
+               } else {
+                       desired_mute_gain = 1.0;
+               }
        }
 }
 
@@ -1114,7 +1154,12 @@ Route::set_mute (bool yn, void *src)
                _mute_control->Changed (); /* EMIT SIGNAL */
                
                Glib::Mutex::Lock lm (declick_lock);
-               desired_mute_gain = (yn?0.0f:1.0f);
+               
+               if (_soloed && Config->get_solo_mute_override()){
+                       desired_mute_gain = 1.0f;
+               } else {
+                       desired_mute_gain = (yn?0.0f:1.0f);
+               }
        }
 }
 
@@ -1184,6 +1229,11 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorStreams*
 int
 Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
 {
+       /* NOTE: this is intended to be used ONLY when copying
+          processors from another Route. Hence the subtle
+          differences between this and ::add_processor()
+       */
+
        ChanCount old_pmo = processor_max_outs;
 
        if (!_session.engine().connected()) {
@@ -1222,7 +1272,6 @@ Route::add_processors (const ProcessorList& others, ProcessorStreams* err)
                                return -1;
                        }
                        
-                       (*i)->activate ();
                        (*i)->ActiveChanged.connect (bind (mem_fun (_session, &Session::update_latency_compensation), false, false));
                }
 
@@ -1248,7 +1297,7 @@ Route::disable_processors (Placement p)
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if ((*i)->placement() == p) {
-                       (*i)->set_active (false);
+                       (*i)->deactivate ();
                }
        }
 
@@ -1264,7 +1313,7 @@ Route::disable_processors ()
        Glib::RWLock::ReaderLock lm (_processor_lock);
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->set_active (false);
+               (*i)->deactivate ();
        }
        
        _session.set_dirty ();
@@ -1281,7 +1330,7 @@ Route::disable_plugins (Placement p)
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i) && (*i)->placement() == p) {
-                       (*i)->set_active (false);
+                       (*i)->deactivate ();
                }
        }
        
@@ -1298,7 +1347,7 @@ Route::disable_plugins ()
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
-                       (*i)->set_active (false);
+                       (*i)->deactivate ();
                }
        }
        
@@ -1323,7 +1372,7 @@ Route::ab_plugins (bool forward)
                        }
 
                        if ((*i)->active()) {
-                               (*i)->set_active (false);
+                               (*i)->deactivate ();
                                (*i)->set_next_ab_is_active (true);
                        } else {
                                (*i)->set_next_ab_is_active (false);
@@ -1341,9 +1390,9 @@ Route::ab_plugins (bool forward)
                        }
 
                        if ((*i)->get_next_ab_is_active()) {
-                               (*i)->set_active (true);
+                               (*i)->activate ();
                        } else {
-                               (*i)->set_active (false);
+                               (*i)->deactivate ();
                        }
                }
        }
@@ -1358,9 +1407,10 @@ Route::pre_fader_streams() const
 {
        boost::shared_ptr<Processor> processor;
 
-       // Find the last pre-fader redirect
+       /* Find the last pre-fader redirect that isn't a send; sends don't affect the number
+        * of streams. */
        for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               if ((*i)->placement() == PreFader) {
+               if ((*i)->placement() == PreFader && boost::dynamic_pointer_cast<Send> (*i) == 0) {
                        processor = *i;
                }
        }
@@ -1551,7 +1601,7 @@ Route::_reset_processor_counts (ProcessorStreams* err)
                        plugin_insert->set_count (1);
 
                } else if ((port_insert = boost::dynamic_pointer_cast<PortInsert>(*r)) != 0) {
-                       
+
                        ++insert_cnt;
                        proc_map[(*r)->placement()].push_back (ProcessorCount (*r));
 
@@ -1559,7 +1609,7 @@ Route::_reset_processor_counts (ProcessorStreams* err)
                        ++send_cnt;
                }
        }
-       
+
        if (insert_cnt == 0) {
                if (send_cnt) {
                        goto recompute;
@@ -1582,7 +1632,7 @@ Route::_reset_processor_counts (ProcessorStreams* err)
        if (!proc_map[PreFader].empty()) {
                previous_initial_streams = n_inputs ();
                for (list<ProcessorCount>::iterator i = proc_map[PreFader].begin(); i != proc_map[PreFader].end(); i++) {
-                       if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) < 0) {
+                       if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) == false) {
                                goto streamcount;
                        }
                        previous_initial_streams = initial_streams;
@@ -1597,7 +1647,7 @@ Route::_reset_processor_counts (ProcessorStreams* err)
 
        if (!proc_map[PostFader].empty()) {
                for (list<ProcessorCount>::iterator i = proc_map[PostFader].begin(); i != proc_map[PostFader].end(); i++) {
-                       if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) < 0) {
+                       if (i->processor->can_support_io_configuration (previous_initial_streams, initial_streams) == false) {
                                goto streamcount;
                        }
                        previous_initial_streams = initial_streams;
@@ -1622,6 +1672,11 @@ Route::_reset_processor_counts (ProcessorStreams* err)
                boost::shared_ptr<Send> s;
 
                if ((s = boost::dynamic_pointer_cast<Send> (*r)) != 0) {
+
+                       /* don't pay any attention to send output configuration, since it doesn't
+                          affect the route.
+                        */
+
                        if (r == _processors.begin()) {
                                s->expect_inputs (n_inputs());
                        } else {
@@ -1630,10 +1685,6 @@ Route::_reset_processor_counts (ProcessorStreams* err)
 
                } else {
                        
-                       /* don't pay any attention to send output configuration, since it doesn't
-                          affect the route.
-                        */
-                       
                        max_audio = max ((*r)->output_streams ().n_audio(), max_audio);
                        max_midi = max ((*r)->output_streams ().n_midi(), max_midi);
                }
@@ -1666,8 +1717,6 @@ Route::apply_some_processor_counts (list<ProcessorCount>& iclist)
 
                ProcessorCount& pc (*i);
 
-               cerr << "now applying for " << (*i).processor->name() << " in = " << pc.in.n_audio() << " out = " << pc.out.n_audio() << endl;
-
                if (pc.processor->configure_io (pc.in, pc.out)) {
                        return -1;
                }
@@ -1698,8 +1747,6 @@ Route::check_some_processor_counts (list<ProcessorCount>& iclist, ChanCount requ
 
        for (i = iclist.begin(); i != iclist.end(); ++i, ++index) {
 
-               cerr << "Checking whether " << (*i).processor->name() << " can support " << required_inputs.n_audio() << " inputs\n";
-
                if (!(*i).processor->can_support_io_configuration (required_inputs, (*i).out)) {
                        if (err) {
                                err->index = index;
@@ -1715,87 +1762,6 @@ Route::check_some_processor_counts (list<ProcessorCount>& iclist, ChanCount requ
        return false;
 }
 
-int
-Route::copy_processors (const Route& other, Placement placement, ProcessorStreams* err)
-{
-       ChanCount old_pmo = processor_max_outs;
-
-       ProcessorList to_be_deleted;
-
-       {
-               Glib::RWLock::WriterLock lm (_processor_lock);
-               ProcessorList::iterator tmp;
-               ProcessorList the_copy;
-
-               the_copy = _processors;
-               
-               /* remove all relevant processors */
-
-               for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ) {
-                       tmp = i;
-                       ++tmp;
-
-                       if ((*i)->placement() == placement) {
-                               to_be_deleted.push_back (*i);
-                               _processors.erase (i);
-                       }
-
-                       i = tmp;
-               }
-
-               /* now copy the relevant ones from "other" */
-               
-               for (ProcessorList::const_iterator i = other._processors.begin(); i != other._processors.end(); ++i) {
-                       if ((*i)->placement() == placement) {
-                               _processors.push_back (IOProcessor::clone (*i));
-                       }
-               }
-
-               /* reset plugin stream handling */
-
-               if (_reset_processor_counts (err)) {
-
-                       /* FAILED COPY ATTEMPT: we have to restore order */
-
-                       /* delete all cloned processors */
-
-                       for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ) {
-
-                               tmp = i;
-                               ++tmp;
-
-                               if ((*i)->placement() == placement) {
-                                       _processors.erase (i);
-                               }
-                               
-                               i = tmp;
-                       }
-
-                       /* restore the natural order */
-
-                       _processors = the_copy;
-                       processor_max_outs = old_pmo;
-
-                       /* we failed, even though things are OK again */
-
-                       return -1;
-
-               } else {
-                       
-                       /* SUCCESSFUL COPY ATTEMPT: delete the processors we removed pre-copy */
-                       to_be_deleted.clear ();
-                       _user_latency = 0;
-               }
-       }
-
-       if (processor_max_outs != old_pmo || old_pmo == ChanCount::ZERO) {
-               reset_panner ();
-       }
-
-       processors_changed (); /* EMIT SIGNAL */
-       return 0;
-}
-
 void
 Route::all_processors_flip ()
 {
@@ -1808,7 +1774,11 @@ Route::all_processors_flip ()
        bool first_is_on = _processors.front()->active();
        
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
-               (*i)->set_active (!first_is_on);
+               if (first_is_on) {
+                       (*i)->deactivate ();
+               } else {
+                       (*i)->activate ();
+               }
        }
        
        _session.set_dirty ();
@@ -1829,7 +1799,11 @@ Route::all_processors_active (Placement p, bool state)
 
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
                if ((*i)->placement() == p) {
-                       (*i)->set_active (state);
+                       if (state) {
+                               (*i)->activate ();
+                       } else {
+                               (*i)->deactivate ();
+                       }
                }
        }
        
@@ -1902,7 +1876,8 @@ Route::state(bool full_state)
        node->add_property("mute-affects-pre-fader", _mute_affects_pre_fader?"yes":"no"); 
        node->add_property("mute-affects-post-fader", _mute_affects_post_fader?"yes":"no"); 
        node->add_property("mute-affects-control-outs", _mute_affects_control_outs?"yes":"no"); 
-       node->add_property("mute-affects-main-outs", _mute_affects_main_outs?"yes":"no"); 
+       node->add_property("mute-affects-main-outs", _mute_affects_main_outs?"yes":"no");
+       node->add_property("meter-point", enum_2_string (_meter_point));
 
        if (_edit_group) {
                node->add_property("edit-group", _edit_group->name());
@@ -2192,6 +2167,10 @@ Route::_set_state (const XMLNode& node, bool call_base)
                _mute_affects_main_outs = (prop->value()=="yes")?true:false;
        }
 
+       if ((prop = node.property (X_("meter-point"))) != 0) {
+               _meter_point = MeterPoint (string_2_enum (prop->value (), _meter_point));
+       }
+       
        if ((prop = node.property (X_("edit-group"))) != 0) {
                RouteGroup* edit_group = _session.edit_group_by_name(prop->value());
                if(edit_group == 0) {
@@ -2234,10 +2213,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
 
        nlist = node.children();
 
-       if (deferred_state) {
-               delete deferred_state;
-       }
-
+       delete deferred_state;
        deferred_state = new XMLNode(X_("deferred state"));
 
        /* set parent class properties before anything else */
@@ -2283,6 +2259,7 @@ Route::_set_state (const XMLNode& node, bool call_base)
                        string coutname = _name;
                        coutname += _("[control]");
 
+                       delete _control_outs;
                        _control_outs = new IO (_session, coutname);
                        _control_outs->set_state (**(child->children().begin()));
 
@@ -2480,10 +2457,8 @@ Route::set_control_outs (const vector<string>& ports)
        vector<string>::const_iterator i;
        size_t limit;
        
-       if (_control_outs) {
-               delete _control_outs;
-               _control_outs = 0;
-       }
+       delete _control_outs;
+       _control_outs = 0;
 
        if (is_control() || is_master()) {
                /* no control outs for these two special busses */
@@ -3077,3 +3052,50 @@ Route::set_pending_declick (int declick)
 
 }
 
+/** Shift automation forwards from a particular place, thereby inserting time.
+ *  Adds undo commands for any shifts that are performed.
+ *
+ * @param pos Position to start shifting from.
+ * @param frames Amount to shift forwards by.
+ */
+
+void
+Route::shift (nframes64_t pos, nframes64_t frames)
+{
+#ifdef THIS_NEEDS_FIXING_FOR_V3
+
+       /* gain automation */
+       XMLNode &before = _gain_control->get_state ();
+       _gain_control->shift (pos, frames);
+       XMLNode &after = _gain_control->get_state ();
+       _session.add_command (new MementoCommand<AutomationList> (_gain_automation_curve, &before, &after));
+
+       /* pan automation */
+       for (std::vector<StreamPanner*>::iterator i = _panner->begin (); i != _panner->end (); ++i) {
+               Curve & c = (*i)->automation ();
+               XMLNode &before = c.get_state ();
+               c.shift (pos, frames);
+               XMLNode &after = c.get_state ();
+               _session.add_command (new MementoCommand<AutomationList> (c, &before, &after));
+       }
+
+       /* redirect automation */
+       {
+               Glib::RWLock::ReaderLock lm (redirect_lock);
+               for (RedirectList::iterator i = _redirects.begin (); i != _redirects.end (); ++i) {
+                       
+                       set<uint32_t> a;
+                       (*i)->what_has_automation (a);
+                       
+                       for (set<uint32_t>::const_iterator j = a.begin (); j != a.end (); ++j) {
+                               AutomationList & al = (*i)->automation_list (*j);
+                               XMLNode &before = al.get_state ();
+                               al.shift (pos, frames);
+                               XMLNode &after = al.get_state ();
+                               _session.add_command (new MementoCommand<AutomationList> (al, &before, &after));
+                       }
+               }
+       }
+#endif
+
+}