integrate Session::remove_routes() from Tracks and replace Session::remove_route...
[ardour.git] / libs / ardour / session.cc
index b1b0b1e1b54d62fa8d9d1c417d229c89923c1664..9df9f1940730ea15a9e300a5b9b9097b3b66dfc4 100644 (file)
@@ -78,6 +78,7 @@
 #include "ardour/plugin.h"
 #include "ardour/plugin_insert.h"
 #include "ardour/process_thread.h"
+#include "ardour/profile.h"
 #include "ardour/rc_configuration.h"
 #include "ardour/recent_sessions.h"
 #include "ardour/region.h"
@@ -243,6 +244,7 @@ Session::Session (AudioEngine &eng,
        , _all_route_group (new RouteGroup (*this, "all"))
        , routes (new RouteList)
        , _adding_routes_in_progress (false)
+       , _route_deletion_in_progress (false)
        , destructive_index (0)
        , _track_number_decimals(1)
        , solo_update_disabled (false)
@@ -268,6 +270,7 @@ Session::Session (AudioEngine &eng,
        , first_file_header_format_reset (true)
        , have_looped (false)
        , _have_rec_enabled_track (false)
+    , _have_rec_disabled_track (true)
        , _step_editors (0)
        , _suspend_timecode_transmission (0)
        ,  _speakers (new Speakers)
@@ -1604,6 +1607,15 @@ Session::location_added (Location *location)
                 _session_range_location = location;
         }
 
+        if (location->is_mark()) {
+                /* listen for per-location signals that require us to do any * global updates for marks */
+
+                location->StartChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+                location->EndChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+                location->Changed.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+                location->FlagsChanged.connect_same_thread (skip_update_connections, boost::bind (&Session::update_marks, this, location));
+        }
+
         if (location->is_skip()) {
                 /* listen for per-location signals that require us to update skip-locate events */
 
@@ -1614,7 +1626,7 @@ Session::location_added (Location *location)
 
                 update_skips (location, true);
         }
-
+        
        set_dirty ();
 }
 
@@ -2198,7 +2210,11 @@ Session::new_midi_track (const ChanCount& input, const ChanCount& output, boost:
   failed:
        if (!new_routes.empty()) {
                StateProtector sp (this);
-               add_routes (new_routes, true, true, true);
+               if (Profile->get_trx()) {
+                       add_routes (new_routes, false, false, false);
+               } else {
+                       add_routes (new_routes, true, true, false);
+               }
 
                if (instrument) {
                        for (RouteList::iterator r = new_routes.begin(); r != new_routes.end(); ++r) {
@@ -2360,6 +2376,43 @@ Session::reconnect_existing_routes (bool withLock, bool reconnect_master, bool r
          */
 }
 
+#ifdef USE_TRACKS_CODE_FEATURES
+
+void
+Session::reconnect_midi_scene_ports(bool inputs)
+{
+       if (inputs) {
+               scene_in()->disconnect_all ();
+        
+               std::vector<EngineStateController::MidiPortState> midi_port_states;
+               EngineStateController::instance()->get_physical_midi_input_states (midi_port_states);
+        
+               std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
+        
+               for (; state_iter != midi_port_states.end(); ++state_iter) {
+                       if (state_iter->active && state_iter->available && state_iter->connected) {
+                               scene_in()->connect (state_iter->name);
+                       }
+               }
+
+       } else {
+               scene_out()->disconnect_all ();
+
+               std::vector<EngineStateController::MidiPortState> midi_port_states;
+               EngineStateController::instance()->get_physical_midi_output_states (midi_port_states);
+        
+               std::vector<EngineStateController::MidiPortState>::iterator state_iter = midi_port_states.begin();
+        
+               for (; state_iter != midi_port_states.end(); ++state_iter) {
+                       if (state_iter->active && state_iter->available && state_iter->connected) {
+                               scene_out()->connect (state_iter->name);
+                       }
+               }
+
+       }
+}
+
+#endif
 
 /** Caller must not hold process lock
  *  @param name_template string to use for the start of the name, or "" to use "Audio".
@@ -2374,10 +2427,19 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
        RouteList new_routes;
        list<boost::shared_ptr<AudioTrack> > ret;
 
-       bool const use_number = (how_many != 1) || name_template.empty () || name_template == _("Audio");
+       string name_pattern;
 
+       if (Profile->get_trx() ) {
+               name_pattern = "Track ";
+       } else {
+               name_pattern = "Audio ";
+       }
+    
+       bool const use_number = (how_many != 1) || name_template.empty () || name_template == _(name_pattern.c_str() );
+       
        while (how_many) {
-               if (!find_route_name (name_template.empty() ? _("Audio") : name_template, ++track_id, track_name, sizeof(track_name), use_number)) {
+
+               if (!find_route_name (name_template.empty() ? _(name_pattern.c_str()) : name_template, ++track_id, track_name, sizeof(track_name), use_number)) {
                        error << "cannot find name for new audio track" << endmsg;
                        goto failed;
                }
@@ -2448,7 +2510,11 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
   failed:
        if (!new_routes.empty()) {
                StateProtector sp (this);
-               add_routes (new_routes, true, true, true);
+               if (Profile->get_trx()) {
+                       add_routes (new_routes, false, false, false);
+               } else {
+                       add_routes (new_routes, true, true, false);
+               }
        }
 
        return ret;
@@ -2534,7 +2600,11 @@ Session::new_audio_route (int input_channels, int output_channels, RouteGroup* r
   failure:
        if (!ret.empty()) {
                StateProtector sp (this);
-               add_routes (ret, false, true, true); // autoconnect outputs only
+               if (Profile->get_trx()) {
+                       add_routes (ret, false, false, false);
+               } else {
+                       add_routes (ret, false, true, true); // autoconnect // outputs only
+               }
        }
 
        return ret;
@@ -2651,7 +2721,11 @@ Session::new_route_from_template (uint32_t how_many, const std::string& template
   out:
        if (!ret.empty()) {
                StateProtector sp (this);
-               add_routes (ret, true, true, true);
+               if (Profile->get_trx()) {
+                       add_routes (ret, false, false, false);
+               } else {
+                       add_routes (ret, true, true, false);
+               }
                IO::enable_connecting ();
        }
 
@@ -2682,6 +2756,8 @@ Session::add_routes (RouteList& new_routes, bool input_auto_connect, bool output
        
        reassign_track_numbers();
 
+       update_route_record_state ();
+    
        RouteAdded (new_routes); /* EMIT SIGNAL */
 }
 
@@ -2739,7 +2815,7 @@ Session::add_routes_inner (RouteList& new_routes, bool input_auto_connect, bool
                if (tr) {
                        tr->PlaylistChanged.connect_same_thread (*this, boost::bind (&Session::track_playlist_changed, this, boost::weak_ptr<Track> (tr)));
                        track_playlist_changed (boost::weak_ptr<Track> (tr));
-                       tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_have_rec_enabled_track, this));
+                       tr->RecordEnableChanged.connect_same_thread (*this, boost::bind (&Session::update_route_record_state, this));
 
                        boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (tr);
                        if (mt) {
@@ -2873,100 +2949,128 @@ Session::add_internal_send (boost::shared_ptr<Route> dest, boost::shared_ptr<Pro
        graph_reordered ();
 }
 
+
 void
-Session::remove_route (boost::shared_ptr<Route> route)
+Session::remove_routes (boost::shared_ptr<RouteList> routes_to_remove)
 {
-       if (route == _master_out) {
-               return;
-       }
-
-       route->set_solo (false, this);
-
-       {
+       { // RCU Writer scope
                RCUWriter<RouteList> writer (routes);
                boost::shared_ptr<RouteList> rs = writer.get_copy ();
-
-               rs->remove (route);
-
-               /* deleting the master out seems like a dumb
-                  idea, but its more of a UI policy issue
-                  than our concern.
-               */
-
-               if (route == _master_out) {
-                       _master_out = boost::shared_ptr<Route> ();
-               }
-
-               if (route == _monitor_out) {
-                       _monitor_out.reset ();
-               }
-
-               /* writer goes out of scope, forces route list update */
-       }
-
-       update_route_solo_state ();
-
-       // We need to disconnect the route's inputs and outputs
-
-       route->input()->disconnect (0);
-       route->output()->disconnect (0);
-
-       /* if the route had internal sends sending to it, remove them */
-       if (route->internal_return()) {
-
-               boost::shared_ptr<RouteList> r = routes.reader ();
-               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
-                       boost::shared_ptr<Send> s = (*i)->internal_send_for (route);
-                       if (s) {
-                               (*i)->remove_processor (s);
+        
+        
+               for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
+            
+                       if (*iter == _master_out) {
+                               continue;
+                       }
+            
+                       (*iter)->set_solo (false, this);
+            
+                       rs->remove (*iter);
+            
+                       /* deleting the master out seems like a dumb
+                          idea, but its more of a UI policy issue
+                          than our concern.
+                       */
+            
+                       if (*iter == _master_out) {
+                               _master_out = boost::shared_ptr<Route> ();
+                       }
+            
+                       if (*iter == _monitor_out) {
+                               _monitor_out.reset ();
                        }
-               }
-       }
 
-       /* if the monitoring section had a pointer to this route, remove it */
-       if (_monitor_out && !route->is_master() && !route->is_monitor()) {
-               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
-               PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
-               route->remove_aux_or_listen (_monitor_out);
-       }
+                       update_route_solo_state ();
+            
+                       // We need to disconnect the route's inputs and outputs
+            
+                       (*iter)->input()->disconnect (0);
+                       (*iter)->output()->disconnect (0);
+            
+                       /* if the route had internal sends sending to it, remove them */
+                       if ((*iter)->internal_return()) {
+                
+                               boost::shared_ptr<RouteList> r = routes.reader ();
+                               for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
+                                       boost::shared_ptr<Send> s = (*i)->internal_send_for (*iter);
+                                       if (s) {
+                                               (*i)->remove_processor (s);
+                                       }
+                               }
+                       }
+            
+                       /* if the monitoring section had a pointer to this route, remove it */
+                       if (_monitor_out && !(*iter)->is_master() && !(*iter)->is_monitor()) {
+                               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
+                               PBD::Unwinder<bool> uw (ignore_route_processor_changes, true);
+                               (*iter)->remove_aux_or_listen (_monitor_out);
+                       }
+            
+                       boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (*iter);
+                       if (mt && mt->step_editing()) {
+                               if (_step_editors > 0) {
+                                       _step_editors--;
+                               }
+                       }
 
-       boost::shared_ptr<MidiTrack> mt = boost::dynamic_pointer_cast<MidiTrack> (route);
-       if (mt && mt->step_editing()) {
-               if (_step_editors > 0) {
-                       _step_editors--;
+                       RouteAddedOrRemoved (false); /* EMIT SIGNAL */
                }
-       }
+    
+               /* writer goes out of scope, forces route list update */
 
+       } // end of RCU Writer scope
+    
        update_latency_compensation ();
        set_dirty();
-
+    
        /* Re-sort routes to remove the graph's current references to the one that is
         * going away, then flush old references out of the graph.
+        * Wave Tracks: reconnect routes
         */
 
-       resort_routes ();
+       if (ARDOUR::Profile->get_trx () ) {
+               reconnect_existing_routes(true, false);
+       } else {
+               resort_routes ();
+       }
+    
        if (_process_graph) {
                _process_graph->clear_other_chain ();
        }
-
+    
        /* get rid of it from the dead wood collection in the route list manager */
-
        /* XXX i think this is unsafe as it currently stands, but i am not sure. (pd, october 2nd, 2006) */
-
+    
        routes.flush ();
+    
+       /* try to cause everyone to drop their references
+        * and unregister ports from the backend
+        */
+       PBD::Unwinder<bool> uw_flag (_route_deletion_in_progress, true);
 
-       /* try to cause everyone to drop their references */
-
-       route->drop_references ();
-
+       for (RouteList::iterator iter = routes_to_remove->begin(); iter != routes_to_remove->end(); ++iter) {
+               (*iter)->drop_references ();
+       }
+    
        Route::RemoteControlIDChange(); /* EMIT SIGNAL */
-
+    
        /* save the new state of the world */
-
+    
        if (save_state (_current_snapshot_name)) {
                save_history (_current_snapshot_name);
        }
+
        reassign_track_numbers();
+       update_route_record_state ();
+}
+
+void
+Session::remove_route (boost::shared_ptr<Route> route)
+{
+       boost::shared_ptr<RouteList> rl (new RouteList);
+       rl->push_back (route);
+       remove_routes (rl);
 }
 
 void
@@ -4951,9 +5055,15 @@ Session::have_rec_enabled_track () const
        return g_atomic_int_get (const_cast<gint*>(&_have_rec_enabled_track)) == 1;
 }
 
+bool
+Session::have_rec_disabled_track () const
+{
+    return g_atomic_int_get (const_cast<gint*>(&_have_rec_disabled_track)) == 1;
+}
+
 /** Update the state of our rec-enabled tracks flag */
 void
-Session::update_have_rec_enabled_track ()
+Session::update_route_record_state ()
 {
        boost::shared_ptr<RouteList> rl = routes.reader ();
        RouteList::iterator i = rl->begin();
@@ -4974,6 +5084,20 @@ Session::update_have_rec_enabled_track ()
        if (g_atomic_int_get (&_have_rec_enabled_track) != old) {
                RecordStateChanged (); /* EMIT SIGNAL */
        }
+
+    
+    i = rl->begin();
+       while (i != rl->end ()) {
+        
+               boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+               if (tr && !tr->record_enabled ()) {
+                       break;
+               }
+        
+               ++i;
+       }
+    
+    g_atomic_int_set (&_have_rec_disabled_track, i != rl->end () ? 1 : 0);
 }
 
 void
@@ -5016,7 +5140,8 @@ Session::route_added_to_route_group (RouteGroup* rg, boost::weak_ptr<Route> r)
 void
 Session::route_removed_from_route_group (RouteGroup* rg, boost::weak_ptr<Route> r)
 {
-       RouteRemovedFromRouteGroup (rg, r);
+       update_route_record_state ();
+       RouteRemovedFromRouteGroup (rg, r); /* EMIT SIGNAL */
 }
 
 boost::shared_ptr<RouteList>