midway snapshot of work done on managing Region & Source lifetimes correctly. may...
[ardour.git] / libs / ardour / session.cc
index 68244c9812d32988f19d8279b1d3e1f65c43c2f2..91b1e2a0f95465e1e7c2a8087b199add54fd4b11 100644 (file)
@@ -1324,10 +1324,9 @@ Session::resort_routes ()
                shared_ptr<RouteList> r = writer.get_copy ();
                resort_routes_using (r);
                /* writer goes out of scope and forces update */
-                route_graph->rechain( r );
        }
 
-       route_graph->dump(1);
+       //route_graph->dump(1);
 
 #ifndef NDEBUG
         boost::shared_ptr<RouteList> rl = routes.reader ();
@@ -1382,6 +1381,8 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
        RouteSorter cmp;
        r->sort (cmp);
 
+       route_graph->rechain( r );
+
 #ifndef NDEBUG
         DEBUG_TRACE (DEBUG::Graph, "Routes resorted, order follows:\n");
        for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
@@ -1483,6 +1484,7 @@ Session::new_midi_track (TrackMode mode, RouteGroup* route_group, uint32_t how_m
                        auto_connect_route (track, existing_inputs, existing_outputs);
 
                        track->non_realtime_input_change();
+
                        if (route_group) {
                                route_group->add (track);
                        }
@@ -1540,9 +1542,6 @@ Session::auto_connect_route (boost::shared_ptr<Route> route,
                ? ChanCount::max(existing_inputs, existing_outputs)
                : existing_outputs;
 
-       static string empty_string;
-       string& port = empty_string;
-
        for (DataType::iterator t = DataType::begin(); t != DataType::end(); ++t) {
                vector<string> physinputs;
                vector<string> physoutputs;
@@ -1553,7 +1552,7 @@ Session::auto_connect_route (boost::shared_ptr<Route> route,
                if (!physinputs.empty()) {
                        uint32_t nphysical_in = physinputs.size();
                        for (uint32_t i = 0; i < route->n_inputs().get(*t) && i < nphysical_in; ++i) {
-                               port = empty_string;
+                               string port;
 
                                if (Config->get_input_auto_connect() & AutoConnectPhysical) {
                                        port = physinputs[(in_offset.get(*t) + i) % nphysical_in];
@@ -1569,7 +1568,7 @@ Session::auto_connect_route (boost::shared_ptr<Route> route,
                if (!physoutputs.empty()) {
                        uint32_t nphysical_out = physoutputs.size();
                        for (uint32_t i = 0; i < route->n_outputs().get(*t); ++i) {
-                               port = empty_string;
+                               string port;
 
                                if (Config->get_output_auto_connect() & AutoConnectPhysical) {
                                        port = physoutputs[(out_offset.get(*t) + i) % nphysical_out];
@@ -2050,6 +2049,10 @@ Session::add_internal_sends (boost::shared_ptr<Route> dest, Placement p, boost::
 void
 Session::remove_route (shared_ptr<Route> route)
 {
+        if (((route == _master_out) || (route == _monitor_out)) && !Config->get_allow_special_bus_removal()) {
+                return;
+        }
+
        {
                RCUWriter<RouteList> writer (routes);
                shared_ptr<RouteList> rs = writer.get_copy ();
@@ -2481,46 +2484,58 @@ Session::find_whole_file_parent (boost::shared_ptr<Region const> child) const
 }
 
 int
-Session::destroy_region (boost::shared_ptr<Region> region)
+Session::destroy_sources (list<boost::shared_ptr<Source> > srcs)
 {
-       vector<boost::shared_ptr<Source> > srcs;
+        set<boost::shared_ptr<Region> > relevant_regions;
 
-       {
-               if (region->playlist()) {
-                       region->playlist()->destroy_region (region);
-               }
-
-               for (uint32_t n = 0; n < region->n_channels(); ++n) {
-                       srcs.push_back (region->source (n));
-               }
+       for (list<boost::shared_ptr<Source> >::iterator s = srcs.begin(); s != srcs.end(); ++s) {
+                RegionFactory::get_regions_using_source (*s, relevant_regions);
        }
 
-       region->drop_references ();
+        cerr << "There are " << relevant_regions.size() << " using " << srcs.size() << " sources" << endl;
 
-       for (vector<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
+        for (set<boost::shared_ptr<Region> >::iterator r = relevant_regions.begin(); r != relevant_regions.end(); ) {
+                set<boost::shared_ptr<Region> >::iterator tmp;
 
-                (*i)->mark_for_remove ();
-                (*i)->drop_references ();
+                tmp = r;
+                ++tmp;
+
+                cerr << "Cleanup " << (*r)->name() << " UC = " << (*r).use_count() << endl;
+
+                playlists->destroy_region (*r);
+                RegionFactory::map_remove (*r);
+
+                (*r)->drop_sources ();
+                (*r)->drop_references ();
+
+                cerr << "\tdone UC = " << (*r).use_count() << endl;
+
+                relevant_regions.erase (r);
+
+                r = tmp;
+        }
+
+       for (list<boost::shared_ptr<Source> >::iterator s = srcs.begin(); s != srcs.end(); ) {
                 
-                cerr << "source was not used by any playlist\n";
-       }
+                {
+                        Glib::Mutex::Lock ls (source_lock);
+                        /* remove from the main source list */
+                        sources.erase ((*s)->id());
+                }
 
-       return 0;
-}
+                (*s)->mark_for_remove ();
+                (*s)->drop_references ();
+
+                s = srcs.erase (s);
+        }
 
-int
-Session::destroy_regions (list<boost::shared_ptr<Region> > regions)
-{
-       for (list<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
-               destroy_region (*i);
-       }
        return 0;
 }
 
 int
 Session::remove_last_capture ()
 {
-       list<boost::shared_ptr<Region> > r;
+       list<boost::shared_ptr<Source> > srcs;
 
        boost::shared_ptr<RouteList> rl = routes.reader ();
        for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
@@ -2529,15 +2544,15 @@ Session::remove_last_capture ()
                        continue;
                }
                
-               list<boost::shared_ptr<Region> >& l = tr->last_capture_regions();
+               list<boost::shared_ptr<Source> >& l = tr->last_capture_sources();
 
                if (!l.empty()) {
-                       r.insert (r.end(), l.begin(), l.end());
+                       srcs.insert (srcs.end(), l.begin(), l.end());
                        l.clear ();
                }
        }
 
-       destroy_regions (r);
+       destroy_sources (srcs);
 
        save_state (_current_snapshot_name);
 
@@ -2561,16 +2576,19 @@ Session::add_source (boost::shared_ptr<Source> source)
        }
 
        if (result.second) {
-               set_dirty();
-       }
 
-       boost::shared_ptr<AudioFileSource> afs;
+                /* yay, new source */
 
-       if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
-               if (Config->get_auto_analyse_audio()) {
-                       Analyser::queue_source_for_analysis (source, false);
-               }
-       }
+               set_dirty();
+
+                boost::shared_ptr<AudioFileSource> afs;
+                
+                if ((afs = boost::dynamic_pointer_cast<AudioFileSource>(source)) != 0) {
+                        if (Config->get_auto_analyse_audio()) {
+                                Analyser::queue_source_for_analysis (source, false);
+                        }
+                }
+        }
 }
 
 void