Fix crash due to incorrect buffer count.
[ardour.git] / libs / ardour / route.cc
index 154c5fd0a06669381eec5c53775726a044c18232..fa4b3ce51d08a72f280bf2acad00e297d96b99bd 100644 (file)
@@ -25,6 +25,7 @@
 #include "pbd/xml++.h"
 #include "pbd/enumwriter.h"
 #include "pbd/memento_command.h"
+#include "pbd/stacktrace.h"
 
 #include "evoral/Curve.hpp"
 
@@ -63,13 +64,15 @@ using namespace ARDOUR;
 using namespace PBD;
 
 uint32_t Route::order_key_cnt = 0;
-boost::signals2::signal<void(string const&)> Route::SyncOrderKeys;
+PBD::Signal1<void,string const&> Route::SyncOrderKeys;
+PBD::Signal0<void> Route::RemoteControlIDChange;
 
 Route::Route (Session& sess, string name, Flag flg, DataType default_type)
        : SessionObject (sess, name)
        , AutomatableControls (sess)
        , _flags (flg)
        , _solo_control (new SoloControllable (X_("solo"), *this))
+       , _mute_control (new MuteControllable (X_("mute"), *this))
        , _mute_master (new MuteMaster (sess, name))
        , _default_type (default_type)
 
@@ -93,13 +96,14 @@ Route::Route (Session& sess, string name, Flag flg, DataType default_type)
 
        /* now that we have _meter, its safe to connect to this */
 
-       scoped_connect (Metering::Meter, (boost::bind (&Route::meter, this)));
+       Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this)));
 }
 
 Route::Route (Session& sess, const XMLNode& node, DataType default_type)
        : SessionObject (sess, "toBeReset")
        , AutomatableControls (sess)
        , _solo_control (new SoloControllable (X_("solo"), *this))
+       , _mute_control (new MuteControllable (X_("mute"), *this))
        , _mute_master (new MuteMaster (sess, "toBeReset"))
        , _default_type (default_type)
 {
@@ -109,7 +113,7 @@ Route::Route (Session& sess, const XMLNode& node, DataType default_type)
 
        /* now that we have _meter, its safe to connect to this */
 
-       scoped_connect (Metering::Meter, (boost::bind (&Route::meter, this)));
+       Metering::Meter.connect_same_thread (*this, (boost::bind (&Route::meter, this)));
 }
 
 void
@@ -139,16 +143,19 @@ Route::init ()
 
        /* add standard controls */
 
+       _solo_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
+       _mute_control->set_flags (Controllable::Flag (_solo_control->flags() | Controllable::Toggle));
+       
        add_control (_solo_control);
-       add_control (_mute_master);
+       add_control (_mute_control);
 
        /* input and output objects */
 
        _input.reset (new IO (_session, _name, IO::Input, _default_type));
        _output.reset (new IO (_session, _name, IO::Output, _default_type));
 
-       scoped_connect (_input->changed, boost::bind (&Route::input_change_handler, this, _1, _2));
-       scoped_connect (_output->changed, boost::bind (&Route::output_change_handler, this, _1, _2));
+       _input->changed.connect_same_thread (*this, boost::bind (&Route::input_change_handler, this, _1, _2));
+       _output->changed.connect_same_thread (*this, boost::bind (&Route::output_change_handler, this, _1, _2));
 
        /* add amp processor  */
 
@@ -160,8 +167,14 @@ Route::~Route ()
 {
        DEBUG_TRACE (DEBUG::Destruction, string_compose ("route %1 destructor\n", _name));
 
+       /* do this early so that we don't get incoming signals as we are going through destruction 
+        */
+
+       drop_connections ();
+
        /* don't use clear_processors here, as it depends on the session which may
-          be half-destroyed by now */
+          be half-destroyed by now 
+       */
 
        Glib::RWLock::WriterLock lm (_processor_lock);
        for (ProcessorList::iterator i = _processors.begin(); i != _processors.end(); ++i) {
@@ -172,11 +185,14 @@ Route::~Route ()
 }
 
 void
-Route::set_remote_control_id (uint32_t id)
+Route::set_remote_control_id (uint32_t id, bool notify_class_listeners)
 {
        if (id != _remote_control_id) {
                _remote_control_id = id;
                RemoteControlIDChanged ();
+               if (notify_class_listeners) {
+                       RemoteControlIDChange ();
+               }
        }
 }
 
@@ -436,11 +452,7 @@ Route::process_output_buffers (BufferSet& bufs,
                        assert (bufs.count() == (*i)->input_streams());
 
                        (*i)->run (bufs, start_frame, end_frame, nframes, *i != _processors.back());
-                       bufs.set_count (ChanCount::max(bufs.count(), (*i)->output_streams()));
-               }
-
-               if (!_processors.empty()) {
-                       bufs.set_count (ChanCount::max (bufs.count(), _processors.back()->output_streams()));
+                       bufs.set_count ((*i)->output_streams());
                }
        }
 }
@@ -792,7 +804,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
                        // XXX: do we want to emit the signal here ? change call order.
                        processor->activate ();
                }
-               scoped_connect (processor->ActiveChanged, boost::bind (&Session::update_latency_compensation, &_session, false, false));
+
+               processor->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false));
 
                _output->set_user_latency (0);
        }
@@ -1047,7 +1060,7 @@ Route::add_processors (const ProcessorList& others, ProcessorList::iterator iter
                                return -1;
                        }
 
-                       scoped_connect ((*i)->ActiveChanged, boost::bind (&Session::update_latency_compensation, &_session, false, false));
+                       (*i)->ActiveChanged.connect_same_thread (*this, boost::bind (&Session::update_latency_compensation, &_session, false, false));
                }
 
                _output->set_user_latency (0);
@@ -2837,14 +2850,60 @@ void
 Route::SoloControllable::set_value (float val)
 {
        bool bval = ((val >= 0.5f) ? true: false);
+# if 0
+       this is how it should be done 
 
+       boost::shared_ptr<RouteList> rl (new RouteList);
+       rl->push_back (route);
+
+       if (Config->get_solo_control_is_listen_control()) {
+               _session.set_listen (rl, bval);
+       } else {
+               _session.set_solo (rl, bval);
+       }
+#else
        route.set_solo (bval, this);
+#endif
 }
 
 float
 Route::SoloControllable::get_value (void) const
 {
-       return route.self_soloed() ? 1.0f : 0.0f;
+       if (Config->get_solo_control_is_listen_control()) {
+               return route.listening() ? 1.0f : 0.0f;
+       } else {
+               return route.self_soloed() ? 1.0f : 0.0f;
+       }
+}
+
+Route::MuteControllable::MuteControllable (std::string name, Route& r)
+       : AutomationControl (r.session(), Evoral::Parameter (MuteAutomation),
+                            boost::shared_ptr<AutomationList>(), name)
+       , route (r)
+{
+       boost::shared_ptr<AutomationList> gl(new AutomationList(Evoral::Parameter(MuteAutomation)));
+       set_list (gl);
+}
+
+void
+Route::MuteControllable::set_value (float val)
+{
+       bool bval = ((val >= 0.5f) ? true: false);
+# if 0
+       this is how it should be done 
+
+       boost::shared_ptr<RouteList> rl (new RouteList);
+       rl->push_back (route);
+       _session.set_mute (rl, bval);
+#else
+       route.set_mute (bval, this);
+#endif
+}
+
+float
+Route::MuteControllable::get_value (void) const
+{
+       return route.muted() ? 1.0f : 0.0f;
 }
 
 void
@@ -3099,3 +3158,40 @@ Route::get_control (const Evoral::Parameter& param)
 
        return c;
 }
+
+boost::shared_ptr<Processor>
+Route::nth_plugin (uint32_t n)
+{
+       Glib::RWLock::ReaderLock lm (_processor_lock);
+       ProcessorList::iterator i;
+
+       for (i = _processors.begin(); i != _processors.end(); ++i) {
+               if (boost::dynamic_pointer_cast<PluginInsert> (*i)) {
+                       if (n-- == 0) {
+                               return *i;
+                       }
+               }
+       }
+
+       return boost::shared_ptr<Processor> ();
+}
+
+boost::shared_ptr<Processor>
+Route::nth_send (uint32_t n)
+{
+       Glib::RWLock::ReaderLock lm (_processor_lock);
+       ProcessorList::iterator i;
+
+       for (i = _processors.begin(); i != _processors.end(); ++i) {
+               cerr << "check " << (*i)->name() << endl;
+               if (boost::dynamic_pointer_cast<Send> (*i)) {
+                       if (n-- == 0) {
+                               return *i;
+                       }
+               } else {
+                       cerr << "\tnot a send\n";
+               }
+       }
+
+       return boost::shared_ptr<Processor> ();
+}