itsy-bitsy freebsd compatibility fix.
[ardour.git] / libs / ardour / session.cc
index f7f5ef7e8d6be1441b94c75acd3a0bac58669537..14c5bde9969045bfbaa674b54eaa1b945d3b1a50 100644 (file)
@@ -40,6 +40,7 @@
 #include <pbd/pathscanner.h>
 #include <pbd/stl_delete.h>
 #include <pbd/basename.h>
+#include <pbd/stacktrace.h>
 
 #include <ardour/audioengine.h>
 #include <ardour/configuration.h>
@@ -278,7 +279,7 @@ Session::Session (AudioEngine &eng,
        
        new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
        if (new_session) {
-               if (create (new_session, mix_template, _engine.frame_rate() * 60 * 5)) {
+               if (create (new_session, mix_template, compute_initial_length())) {
                        cerr << "create failed\n";
                        throw failed_constructor ();
                }
@@ -328,12 +329,21 @@ Session::Session (AudioEngine &eng,
 
        cerr << "Loading session " << fullpath << " using snapshot " << snapshot_name << " (2)" << endl;
 
-       n_physical_outputs = max (requested_physical_out, _engine.n_physical_outputs());
-       n_physical_inputs = max (requested_physical_in, _engine.n_physical_inputs());
+       n_physical_outputs = _engine.n_physical_outputs();
+       n_physical_inputs = _engine.n_physical_inputs();
+
+       if (n_physical_inputs) {
+               n_physical_inputs = max (requested_physical_in, n_physical_inputs);
+       }
+
+       if (n_physical_outputs) {
+               n_physical_outputs = max (requested_physical_out, n_physical_outputs);
+       }
 
        first_stage_init (fullpath, snapshot_name);
 
        new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+
        if (new_session) {
                if (create (new_session, 0, initial_length)) {
                        throw failed_constructor ();
@@ -396,7 +406,7 @@ Session::~Session ()
 
        /* clear history so that no references to objects are held any more */
 
-       history.clear ();
+       _history.clear ();
 
        /* clear state tree so that no references to objects are held any more */
        
@@ -430,6 +440,10 @@ Session::~Session ()
        }
 
        AudioDiskstream::free_working_buffers();
+
+       /* this should cause deletion of the auditioner */
+
+       // auditioner.reset ();
        
 #undef TRACK_DESTRUCTION
 #ifdef TRACK_DESTRUCTION
@@ -463,8 +477,15 @@ Session::~Session ()
        cerr << "delete audio regions\n";
 #endif /* TRACK_DESTRUCTION */
        
-       for (AudioRegionList::iterator i = audio_regions.begin(); i != audio_regions.end(); ++i) {
+       for (AudioRegionList::iterator i = audio_regions.begin(); i != audio_regions.end(); ) {
+               AudioRegionList::iterator tmp;
+
+               tmp = i;
+               ++tmp;
+
                i->second->drop_references ();
+
+               i = tmp;
        }
 
        audio_regions.clear ();
@@ -815,6 +836,11 @@ Session::when_engine_running ()
                }
        }
 
+
+       /* its safe to do this now */
+
+       restore_history (snap_name());
+       
        _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
 
        /* hook us up to the engine */
@@ -1310,8 +1336,10 @@ Session::set_frame_rate (nframes_t frames_per_second)
 
        sync_time_vars();
 
+       Route::set_automation_interval ((jack_nframes_t) ceil ((double) frames_per_second * 0.25));
+
        // XXX we need some equivalent to this, somehow
-       // DestructiveFileSource::setup_standard_crossfades (frames_per_second);
+       // SndFileSource::setup_standard_crossfades (frames_per_second);
 
        set_dirty();
 
@@ -1539,11 +1567,17 @@ Session::resort_routes_using (shared_ptr<RouteList> r)
        
        for (i = r->begin(); i != r->end(); ++i) {
                trace_terminal (*i, *i);
-       }
-       
+       }       
+
        RouteSorter cmp;
        r->sort (cmp);
        
+       /* don't leave dangling references to routes in Route::fed_by */
+
+       for (i = r->begin(); i != r->end(); ++i) {
+               (*i)->fed_by.clear ();
+       }
+
 #if 0
        cerr << "finished route resort\n";
        
@@ -1751,12 +1785,12 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                                      << endmsg;
                        }
                        
-                       for (uint32_t x = 0; x < bus->n_inputs(); ++x) {
+                       for (uint32_t x = 0; n_physical_inputs && x < bus->n_inputs(); ++x) {
                                
                                port = "";
-                               
+
                                if (Config->get_input_auto_connect() & AutoConnectPhysical) {
-                                       port = physinputs[((n+x)%n_physical_inputs)];
+                                               port = physinputs[((n+x)%n_physical_inputs)];
                                } 
                                
                                if (port.length() && bus->connect_input (bus->input (x), port, this)) {
@@ -1764,7 +1798,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
                                }
                        }
                        
-                       for (uint32_t x = 0; x < bus->n_outputs(); ++x) {
+                       for (uint32_t x = 0; n_physical_outputs && x < bus->n_outputs(); ++x) {
                                
                                port = "";
                                
@@ -1877,8 +1911,9 @@ Session::remove_route (shared_ptr<Route> route)
        {       
                RCUWriter<RouteList> writer (routes);
                shared_ptr<RouteList> rs = writer.get_copy ();
-               rs->remove (route);
                
+               rs->remove (route);
+
                /* deleting the master out seems like a dumb
                   idea, but its more of a UI policy issue
                   than our concern.
@@ -2447,15 +2482,21 @@ Session::add_region (boost::shared_ptr<Region> region)
        set_dirty();
        
        if (added) {
-               region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), region));
-               region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), region));
+               region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
+               region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
                AudioRegionAdded (ar); /* EMIT SIGNAL */
        }
 }
 
 void
-Session::region_changed (Change what_changed, boost::shared_ptr<Region> region)
+Session::region_changed (Change what_changed, boost::weak_ptr<Region> weak_region)
 {
+       boost::shared_ptr<Region> region (weak_region.lock ());
+
+       if (!region) {
+               return;
+       }
+
        if (what_changed & Region::HiddenChanged) {
                /* relay hidden changes */
                RegionHiddenChange (region);
@@ -2463,15 +2504,15 @@ Session::region_changed (Change what_changed, boost::shared_ptr<Region> region)
 }
 
 void
-Session::region_renamed (boost::shared_ptr<Region> region)
-{
-       add_region (region);
-}
-
-void
-Session::remove_region (boost::shared_ptr<Region> region)
+Session::remove_region (boost::weak_ptr<Region> weak_region)
 {
        AudioRegionList::iterator i;
+       boost::shared_ptr<Region> region (weak_region.lock ());
+
+       if (!region) {
+               return;
+       }
+
        boost::shared_ptr<AudioRegion> ar;
        bool removed = false;
 
@@ -2482,7 +2523,6 @@ Session::remove_region (boost::shared_ptr<Region> region)
                        if ((i = audio_regions.find (region->id())) != audio_regions.end()) {
                                audio_regions.erase (i);
                                removed = true;
-                               cerr << "done\n";
                        }
 
                } else {
@@ -2501,12 +2541,12 @@ Session::remove_region (boost::shared_ptr<Region> region)
        set_dirty();
 
        if (removed) {
-                AudioRegionRemoved(ar); /* EMIT SIGNAL */
+               AudioRegionRemoved (ar); /* EMIT SIGNAL */
        }
 }
 
 boost::shared_ptr<AudioRegion>
-Session::find_whole_file_parent (boost::shared_ptr<AudioRegion> child)
+Session::find_whole_file_parent (boost::shared_ptr<AudioRegion const> child)
 {
        AudioRegionList::iterator i;
        boost::shared_ptr<AudioRegion> region;
@@ -2524,7 +2564,7 @@ Session::find_whole_file_parent (boost::shared_ptr<AudioRegion> child)
                }
        } 
 
-       return boost::shared_ptr<AudioRegion> ((AudioRegion*) 0);
+       return boost::shared_ptr<AudioRegion> ();
 }      
 
 void
@@ -2537,32 +2577,38 @@ Session::find_equivalent_playlist_regions (boost::shared_ptr<Region> region, vec
 int
 Session::destroy_region (boost::shared_ptr<Region> region)
 {
-       boost::shared_ptr<AudioRegion> aregion;
-
-       if ((aregion = boost::dynamic_pointer_cast<AudioRegion> (region)) == 0) {
-               return 0;
-       }
-       
-       if (aregion->playlist()) {
-               aregion->playlist()->destroy_region (region);
-       }
-
        vector<boost::shared_ptr<Source> > srcs;
-       
-       for (uint32_t n = 0; n < aregion->n_channels(); ++n) {
-               srcs.push_back (aregion->source (n));
+               
+       {
+               boost::shared_ptr<AudioRegion> aregion;
+               
+               if ((aregion = boost::dynamic_pointer_cast<AudioRegion> (region)) == 0) {
+                       return 0;
+               }
+               
+               if (aregion->playlist()) {
+                       aregion->playlist()->destroy_region (region);
+               }
+               
+               for (uint32_t n = 0; n < aregion->n_channels(); ++n) {
+                       srcs.push_back (aregion->source (n));
+               }
        }
 
+       region->drop_references ();
+
        for (vector<boost::shared_ptr<Source> >::iterator i = srcs.begin(); i != srcs.end(); ++i) {
-               
-               if ((*i).use_count() == 1) {
-                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*i);
 
+               if (!(*i)->used()) {
+                       boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource>(*i);
+                       
                        if (afs) {
                                (afs)->mark_for_remove ();
                        }
                        
                        (*i)->drop_references ();
+                       
+                       cerr << "source was not used by any playlist\n";
                }
        }
 
@@ -2954,6 +3000,20 @@ Session::add_playlist (Playlist* playlist)
        PlaylistAdded (playlist); /* EMIT SIGNAL */
 }
 
+void
+Session::get_playlists (vector<Playlist*>& s)
+{
+       { 
+               Glib::Mutex::Lock lm (playlist_lock);
+               for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+                       s.push_back (*i);
+               }
+               for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
+                       s.push_back (*i);
+               }
+       }
+}
+
 void
 Session::track_playlist (Playlist* pl, bool inuse)
 {
@@ -3260,7 +3320,9 @@ Session::remove_redirect (Redirect* redirect)
                } else if ((plugin_insert = dynamic_cast<PluginInsert *> (insert)) != 0) {
                        _plugin_inserts.remove (plugin_insert);
                } else {
-                       fatal << _("programming error: unknown type of Insert deleted!") << endmsg;
+                       fatal << string_compose (_("programming error: %1"),
+                                                X_("unknown type of Insert deleted!")) 
+                             << endmsg;
                        /*NOTREACHED*/
                }
        } else if ((send = dynamic_cast<Send *> (redirect)) != 0) {
@@ -3276,7 +3338,26 @@ Session::remove_redirect (Redirect* redirect)
 nframes_t
 Session::available_capture_duration ()
 {
-       const double scale = 4096.0 / sizeof (Sample);
+       float sample_bytes_on_disk;
+
+       switch (Config->get_native_file_data_format()) {
+       case FormatFloat:
+               sample_bytes_on_disk = 4;
+               break;
+
+       case FormatInt24:
+               sample_bytes_on_disk = 3;
+               break;
+
+       default: 
+               /* impossible, but keep some gcc versions happy */
+               fatal << string_compose (_("programming error: %1"),
+                                        X_("illegal native file data format"))
+                     << endmsg;
+               /*NOTREACHED*/
+       }
+
+       double scale = 4096.0 / sample_bytes_on_disk;
 
        if (_total_free_4k_blocks * scale > (double) max_frames) {
                return max_frames;
@@ -3380,9 +3461,15 @@ Session::ensure_passthru_buffers (uint32_t howmany)
 string
 Session::next_send_name ()
 {
-       char buf[32];
-       snprintf (buf, sizeof (buf), "send %" PRIu32, ++send_cnt);
-       return buf;
+       uint32_t cnt = 0;
+       
+       shared_ptr<RouteList> r = routes.reader ();
+       
+       for (RouteList::const_iterator i = r->begin(); i != r->end(); ++i) {
+               cnt += (*i)->count_sends ();
+       }
+
+       return string_compose (_("send %1"), ++cnt);
 }
 
 string
@@ -3727,13 +3814,14 @@ Session::nbusses () const
 }
 
 void
-Session::add_curve(Curve *curve)
+Session::add_automation_list(AutomationList *al)
 {
-    curves[curve->id()] = curve;
+       automation_lists[al->id()] = al;
 }
 
-void
-Session::add_automation_list(AutomationList *al)
+nframes_t
+Session::compute_initial_length ()
 {
-    automation_lists[al->id()] = al;
+       return _engine.frame_rate() * 60 * 5;
 }
+