Fix copy/paste typo -- MacOSX builds
[ardour.git] / libs / ardour / route.cc
index 3d34b92d2c2780377327093676ec851aa46ff2de..44d79587405749badf5e689a954e16d3c91a23f8 100644 (file)
@@ -46,6 +46,7 @@
 #include "ardour/capturing_processor.h"
 #include "ardour/debug.h"
 #include "ardour/delivery.h"
+#include "ardour/event_type_map.h"
 #include "ardour/gain_control.h"
 #include "ardour/internal_return.h"
 #include "ardour/internal_send.h"
@@ -117,6 +118,11 @@ Route::Route (Session& sess, string name, PresentationInfo::Flag flag, DataType
        processor_max_streams.reset();
 }
 
+boost::weak_ptr<Route>
+Route::weakroute () {
+       return boost::weak_ptr<Route> (shared_from_this ());
+}
+
 int
 Route::init ()
 {
@@ -622,6 +628,9 @@ void
 Route::set_listen (bool yn)
 {
        if (_monitor_send) {
+               if (_monitor_send->active() == yn) {
+                       return;
+               }
                if (yn) {
                        _monitor_send->activate ();
                } else {
@@ -831,6 +840,7 @@ Route::add_processor_from_xml_2X (const XMLNode& node, int version)
                                if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                                prop->value() == "lv2" ||
                                                prop->value() == "windows-vst" ||
+                                               prop->value() == "mac-vst" ||
                                                prop->value() == "lxvst" ||
                                                prop->value() == "audiounit") {
 
@@ -895,6 +905,13 @@ int
 Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor> before, ProcessorStreams* err)
 {
        ProcessorList::iterator loc;
+       boost::shared_ptr <PluginInsert> fanout;
+
+       if (g_atomic_int_get (&_pending_process_reorder)) {
+               /* we need to flush any pending re-order changes */
+               Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
+               apply_processor_changes_rt ();
+       }
 
        if (before) {
                loc = find(_processors.begin(), _processors.end(), before);
@@ -953,7 +970,8 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
 
                if (flags != None) {
                        boost::optional<int> rv = PluginSetup (shared_from_this (), pi, flags);  /* EMIT SIGNAL */
-                       switch (rv.get_value_or (0)) {
+                       int mode = rv.get_value_or (0);
+                       switch (mode & 3) {
                                case 1:
                                        to_skip.push_back (*i); // don't add this one;
                                        break;
@@ -964,6 +982,9 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
                                default:
                                        break;
                        }
+                       if ((mode & 5) == 4) {
+                               fanout = pi;
+                       }
                }
        }
 
@@ -1050,6 +1071,11 @@ Route::add_processors (const ProcessorList& others, boost::shared_ptr<Processor>
        processors_changed (RouteProcessorChange ()); /* EMIT SIGNAL */
        set_processor_positions ();
 
+       if (fanout && fanout->configured ()
+                       && fanout->output_streams().n_audio() > 2
+                       && boost::dynamic_pointer_cast<PluginInsert> (the_instrument ()) == fanout) {
+               fan_out (); /* EMIT SIGNAL */
+       }
        return 0;
 }
 
@@ -1653,13 +1679,21 @@ Route::try_configure_processors_unlocked (ChanCount in, ProcessorStreams* err)
                        if (is_monitor()) {
                                // restriction for Monitor Section Processors
                                if (in.n_audio() != out.n_audio() || out.n_midi() > 0) {
-                                       /* do not allow to add/remove channels (for now)
-                                        * The Monitor follows the master-bus and has no panner (unpan)
-                                        * but do allow processors with midi-in to be added (e.g VSTs with control that
-                                        * will remain unconnected)
+                                       /* Note: The Monitor follows the master-bus and has no panner.
+                                        *
+                                        * The general idea is to only allow plugins that retain the channel-count
+                                        * and plugins with MIDI in (e.g VSTs with control that will remain unconnected).
+                                        * Then again 5.1 in, monitor stereo is a valid use-case.
+                                        *
+                                        * and worse: we only refuse adding plugins *here*.
+                                        *
+                                        * 1) stereo-master, stereo-mon, add a stereo-plugin, OK
+                                        * 2) change master-bus, add a channel
+                                        * 2a) monitor-secion follows
+                                        * 3) monitor processors fail to re-reconfigure (stereo plugin)
+                                        * 4) re-load session, monitor-processor remains unconfigured, crash.
                                         */
-                                       DEBUG_TRACE (DEBUG::Processors, "Monitor: Channel configuration not allowed.\n");
-                                       return list<pair<ChanCount, ChanCount> > ();
+                                       DEBUG_TRACE (DEBUG::Processors, "Monitor: Channel configuration change.\n");
                                }
                                if (boost::dynamic_pointer_cast<InternalSend> (*p)) {
                                        // internal sends make no sense, only feedback
@@ -1952,6 +1986,35 @@ Route::apply_processor_order (const ProcessorList& new_order)
        maybe_note_meter_position ();
 }
 
+void
+Route::move_instrument_down (bool postfader)
+{
+       Glib::Threads::RWLock::ReaderLock lm (_processor_lock);
+       ProcessorList new_order;
+       boost::shared_ptr<Processor> instrument;
+       for (ProcessorList::const_iterator i = _processors.begin(); i != _processors.end(); ++i) {
+               boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert>(*i);
+               if (pi && pi->plugin ()->get_info ()->is_instrument ()) {
+                       instrument = *i;
+               } else if (instrument && *i == _amp) {
+                       if (postfader) {
+                               new_order.push_back (*i);
+                               new_order.push_back (instrument);
+                       } else {
+                               new_order.push_back (instrument);
+                               new_order.push_back (*i);
+                       }
+               } else {
+                       new_order.push_back (*i);
+               }
+       }
+       if (!instrument) {
+               return;
+       }
+       lm.release ();
+       reorder_processors (new_order, 0);
+}
+
 int
 Route::reorder_processors (const ProcessorList& new_order, ProcessorStreams* err)
 {
@@ -2225,7 +2288,6 @@ Route::state(bool full_state)
 {
        LocaleGuard lg;
        if (!_session._template_state_dir.empty()) {
-               assert (!full_state); // only for templates
                foreach_processor (sigc::bind (sigc::mem_fun (*this, &Route::set_plugin_state_dir), _session._template_state_dir));
        }
 
@@ -2464,6 +2526,14 @@ Route::set_state (const XMLNode& node, int version)
                                _mute_control->set_state (*child, version);
                        } else if (prop->value() == _phase_control->name()) {
                                _phase_control->set_state (*child, version);
+                       } else {
+                               Evoral::Parameter p = EventTypeMap::instance().from_symbol (prop->value());
+                               if (p.type () >= MidiCCAutomation && p.type () < MidiSystemExclusiveAutomation) {
+                                       boost::shared_ptr<AutomationControl> ac = automation_control (p, true);
+                                       if (ac) {
+                                               ac->set_state (*child, version);
+                                       }
+                               }
                        }
                } else if (child->name() == MuteMaster::xml_node_name) {
                        _mute_master->set_state (*child, version);
@@ -2754,6 +2824,7 @@ Route::set_processor_state (const XMLNode& node)
                                } else if (prop->value() == "ladspa" || prop->value() == "Ladspa" ||
                                           prop->value() == "lv2" ||
                                           prop->value() == "windows-vst" ||
+                                          prop->value() == "mac-vst" ||
                                           prop->value() == "lxvst" ||
                                           prop->value() == "luaproc" ||
                                           prop->value() == "audiounit") {
@@ -3318,46 +3389,56 @@ Route::output_change_handler (IOChange change, void * /*src*/)
                io_changed (); /* EMIT SIGNAL */
        }
 
-       if (_solo_control->soloed_by_others_downstream()) {
-               int sbod = 0;
-               /* checking all all downstream routes for
-                * explicit of implict solo is a rather drastic measure,
-                * ideally the input_change_handler() of the other route
-                * would propagate the change to us.
+       if ((change.type & IOChange::ConnectionsChanged)) {
+
+               /* do this ONLY if connections have changed. Configuration
+                * changes do not, by themselves alter solo upstream or
+                * downstream status.
                 */
-               boost::shared_ptr<RouteList> routes = _session.get_routes ();
-               if (_output->connected()) {
-                       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
-                               if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
-                                       continue;
-                               }
-                               bool sends_only;
-                               bool does_feed = direct_feeds_according_to_reality (*i, &sends_only);
-                               if (does_feed && !sends_only) {
-                                       if ((*i)->soloed()) {
-                                               ++sbod;
-                                               break;
+
+               if (_solo_control->soloed_by_others_downstream()) {
+                       int sbod = 0;
+                       /* checking all all downstream routes for
+                        * explicit of implict solo is a rather drastic measure,
+                        * ideally the input_change_handler() of the other route
+                        * would propagate the change to us.
+                        */
+                       boost::shared_ptr<RouteList> routes = _session.get_routes ();
+                       if (_output->connected()) {
+                               for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+                                       if ((*i).get() == this || (*i)->is_master() || (*i)->is_monitor() || (*i)->is_auditioner()) {
+                                               continue;
+                                       }
+                                       bool sends_only;
+                                       bool does_feed = direct_feeds_according_to_reality (*i, &sends_only);
+                                       if (does_feed && !sends_only) {
+                                               if ((*i)->soloed()) {
+                                                       ++sbod;
+                                                       break;
+                                               }
                                        }
                                }
                        }
-               }
-               int delta = sbod - _solo_control->soloed_by_others_downstream();
-               if (delta <= 0) {
-                       // do not allow new connections to change implicit solo (no propagation)
-                       _solo_control->mod_solo_by_others_downstream (delta);
-                       // Session::route_solo_changed() does not propagate indirect solo-changes
-                       // propagate upstream to tracks
-                       for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
-                               if ((*i).get() == this || !can_solo()) {
-                                       continue;
-                               }
-                               bool sends_only;
-                               bool does_feed = (*i)->feeds (shared_from_this(), &sends_only);
-                               if (delta != 0 && does_feed && !sends_only) {
-                                       (*i)->solo_control()->mod_solo_by_others_downstream (delta);
+
+                       int delta = sbod - _solo_control->soloed_by_others_downstream();
+                       if (delta <= 0) {
+                               // do not allow new connections to change implicit solo (no propagation)
+                               _solo_control->mod_solo_by_others_downstream (delta);
+                               // Session::route_solo_changed() does not propagate indirect solo-changes
+                               // propagate upstream to tracks
+                               boost::shared_ptr<Route> shared_this = shared_from_this();
+                               for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
+                                       if ((*i).get() == this || !can_solo()) {
+                                               continue;
+                                       }
+                                       bool sends_only;
+                                       bool does_feed = (*i)->feeds (shared_this, &sends_only);
+                                       if (delta != 0 && does_feed && !sends_only) {
+                                               (*i)->solo_control()->mod_solo_by_others_downstream (delta);
+                                       }
                                }
-                       }
 
+                       }
                }
        }
 }
@@ -5259,11 +5340,5 @@ Route::muted_by_others_soloing () const
 void
 Route::clear_all_solo_state ()
 {
-       double v = _solo_safe_control->get_value ();
-
        _solo_control->clear_all_solo_state ();
-
-       if (v != 0.0) {
-               _solo_safe_control->set_value (v, Controllable::NoGroup);
-       }
 }