AccessAction() OSC patch from Ryan Scott
[ardour.git] / libs / ardour / session.cc
index 2534e58d0078a19bf7fe64541a1097d91c23a5c3..5b8d2f850677abea63df09685b996c7960d0e8f7 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <glibmm/thread.h>
 #include <glibmm/miscutils.h>
+#include <glibmm/fileutils.h>
 
 #include <pbd/error.h>
 #include <glibmm/thread.h>
@@ -45,6 +46,7 @@
 #include <ardour/audioengine.h>
 #include <ardour/configuration.h>
 #include <ardour/session.h>
+#include <ardour/analyser.h>
 #include <ardour/audio_diskstream.h>
 #include <ardour/utils.h>
 #include <ardour/audioplaylist.h>
@@ -95,19 +97,29 @@ const char* Session::dead_sound_dir_name = X_("dead_sounds");
 const char* Session::interchange_dir_name = X_("interchange");
 const char* Session::export_dir_name = X_("export");
 
+bool Session::_disable_all_loaded_plugins = false;
+
 Session::compute_peak_t                        Session::compute_peak           = 0;
 Session::find_peaks_t                  Session::find_peaks             = 0;
 Session::apply_gain_to_buffer_t                Session::apply_gain_to_buffer   = 0;
 Session::mix_buffers_with_gain_t       Session::mix_buffers_with_gain  = 0;
 Session::mix_buffers_no_gain_t         Session::mix_buffers_no_gain    = 0;
 
+sigc::signal<void,std::string> Session::Dialog;
 sigc::signal<int> Session::AskAboutPendingState;
+sigc::signal<int,nframes_t,nframes_t> Session::AskAboutSampleRateMismatch;
 sigc::signal<void> Session::SendFeedback;
 
 sigc::signal<void> Session::SMPTEOffsetChanged;
 sigc::signal<void> Session::StartTimeChanged;
 sigc::signal<void> Session::EndTimeChanged;
 
+sigc::signal<void> Session::AutoBindingOn;
+sigc::signal<void> Session::AutoBindingOff;
+
+
+sigc::signal<void, std::string, std::string> Session::Exported;
+
 int
 Session::find_session (string str, string& path, string& snapshot, bool& isnew)
 {
@@ -288,10 +300,10 @@ Session::Session (AudioEngine &eng,
 
        first_stage_init (fullpath, snapshot_name);
        
-       new_session = !g_file_test (_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+       new_session = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
+
        if (new_session) {
                if (create (new_session, mix_template, compute_initial_length())) {
-                       cerr << "create failed\n";
                        destroy ();
                        throw failed_constructor ();
                }
@@ -391,7 +403,7 @@ Session::Session (AudioEngine &eng,
                }
                
                if (!rl.empty()) {
-                       add_routes (rl);
+                       add_routes (rl, false);
                }
                
        }
@@ -404,17 +416,12 @@ Session::Session (AudioEngine &eng,
                throw failed_constructor ();
        }
        
-       store_recent_sessions(_name, _path);
+       store_recent_sessions (_name, _path);
        
-       bool was_dirty = dirty ();
-
        _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
 
-       Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed));
 
-       if (was_dirty) {
-               DirtyChanged (); /* EMIT SIGNAL */
-       }
+       Config->ParameterChanged.connect (mem_fun (*this, &Session::config_changed));
 }
 
 Session::~Session ()
@@ -432,6 +439,7 @@ Session::destroy ()
        remove_pending_capture_state ();
 
        _state_of_the_state = StateOfTheState (CannotSave|Deletion);
+
        _engine.remove_session ();
 
        GoingAway (); /* EMIT SIGNAL */
@@ -576,14 +584,13 @@ Session::destroy ()
 
                tmp = i;
                ++tmp;
-
+               
                i->second->drop_references ();
-
+               
                i = tmp;
        }
-
        audio_sources.clear ();
-
+       
 #ifdef TRACK_DESTRUCTION
        cerr << "delete mix groups\n";
 #endif /* TRACK_DESTRUCTION */
@@ -666,9 +673,13 @@ Session::when_engine_running ()
 
        /* we don't want to run execute this again */
 
+       BootMessage (_("Set block size and sample rate"));
+
        set_block_size (_engine.frames_per_cycle());
        set_frame_rate (_engine.frame_rate());
 
+       BootMessage (_("Using configuration"));
+
        Config->map_parameters (mem_fun (*this, &Session::config_changed));
 
        /* every time we reconnect, recompute worst case output latencies */
@@ -724,6 +735,8 @@ Session::when_engine_running ()
                error << _("cannot setup Click I/O") << endmsg;
        }
 
+       BootMessage (_("Compute I/O Latencies"));
+
        set_worst_io_latencies ();
 
        if (_clicking) {
@@ -734,6 +747,8 @@ Session::when_engine_running ()
           to the physical outputs currently available
        */
 
+       BootMessage (_("Set up standard connections"));
+
        /* ONE: MONO */
 
        for (uint32_t np = 0; np < n_physical_audio_outputs; ++np) {
@@ -838,11 +853,15 @@ Session::when_engine_running ()
                }
                add_connection (c);
        } 
+       
+       BootMessage (_("Setup signal flow and plugins"));
 
        hookup_io ();
 
        /* catch up on send+insert cnts */
 
+       BootMessage (_("Catch up with send/insert state"));
+
        insert_cnt = 0;
        
        for (list<PortInsert*>::iterator i = _port_inserts.begin(); i != _port_inserts.end(); ++i) {
@@ -872,17 +891,18 @@ Session::when_engine_running ()
 
        /* hook us up to the engine */
 
+       BootMessage (_("Connect to engine"));
+
        _engine.set_session (this);
 
 #ifdef HAVE_LIBLO
        /* and to OSC */
 
+       BootMessage (_("OSC startup"));
+
        osc->set_session (*this);
 #endif
     
-       _state_of_the_state = Clean;
-
-       DirtyChanged (); /* EMIT SIGNAL */
 }
 
 void
@@ -894,6 +914,7 @@ Session::hookup_io ()
 
        _state_of_the_state = StateOfTheState (_state_of_the_state | InitialConnecting);
 
+
        if (auditioner == 0) {
                
                /* we delay creating the auditioner till now because
@@ -963,6 +984,7 @@ Session::hookup_io ()
 
        _state_of_the_state = StateOfTheState (_state_of_the_state & ~InitialConnecting);
 
+
        /* now handle the whole enchilada as if it was one
           graph reorder event.
        */
@@ -1106,7 +1128,6 @@ Session::auto_loop_changed (Location* location)
        }       
 
        last_loopend = location->end();
-       
 }
 
 void
@@ -1144,6 +1165,10 @@ Session::set_auto_punch_location (Location* location)
        auto_punch_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_punch_changed));
 
        location->set_auto_punch (true, this);
+
+
+       auto_punch_changed (location);
+
        auto_punch_location_changed (location);
 }
 
@@ -1183,6 +1208,13 @@ Session::set_auto_loop_location (Location* location)
        auto_loop_changed_connection = location->changed.connect (mem_fun (this, &Session::auto_loop_changed));
 
        location->set_auto_loop (true, this);
+
+       /* take care of our stuff first */
+
+       auto_loop_changed (location);
+
+       /* now tell everyone else */
+
        auto_loop_location_changed (location);
 }
 
@@ -1295,11 +1327,11 @@ Session::step_back_from_record ()
        if (g_atomic_int_get (&_record_status) == Recording) {
                g_atomic_int_set (&_record_status, Enabled);
 
-               if (Config->get_monitoring_model() == HardwareMonitoring) {
+               if (Config->get_monitoring_model() == HardwareMonitoring && Config->get_auto_input()) {
                        boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
                        
                        for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
-                               if (Config->get_auto_input() && (*i)->record_enabled ()) {
+                               if ((*i)->record_enabled ()) {
                                        //cerr << "switching from input" << __FILE__ << __LINE__ << endl << endl;
                                        (*i)->monitor_input (false);   
                                }
@@ -1823,8 +1855,7 @@ Session::new_audio_track (int input_channels, int output_channels, TrackMode mod
 
   failed:
        if (!new_routes.empty()) {
-               add_routes (new_routes, false);
-               save_state (_current_snapshot_name);
+               add_routes (new_routes, true);
        }
 
        return ret;
@@ -1958,8 +1989,7 @@ Session::new_audio_route (int input_channels, int output_channels, uint32_t how_
 
   failure:
        if (!ret.empty()) {
-               add_routes (ret, false);
-               save_state (_current_snapshot_name);
+               add_routes (ret, true);
        }
 
        return ret;
@@ -2568,6 +2598,14 @@ Session::region_name (string& result, string base, bool newlevel) const
 
 void
 Session::add_region (boost::shared_ptr<Region> region)
+{
+       vector<boost::shared_ptr<Region> > v;
+       v.push_back (region);
+       add_regions (v);
+}
+               
+void
+Session::add_regions (vector<boost::shared_ptr<Region> >& new_regions)
 {
        boost::shared_ptr<AudioRegion> ar;
        boost::shared_ptr<AudioRegion> oar;
@@ -2576,43 +2614,52 @@ Session::add_region (boost::shared_ptr<Region> region)
        { 
                Glib::Mutex::Lock lm (region_lock);
 
-               if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
-
-                       AudioRegionList::iterator x;
-
-                       for (x = audio_regions.begin(); x != audio_regions.end(); ++x) {
-
-                               oar = boost::dynamic_pointer_cast<AudioRegion> (x->second);
-
-                               if (ar->region_list_equivalent (oar)) {
-                                       break;
-                               }
-                       }
-
-                       if (x == audio_regions.end()) {
-
-                               pair<AudioRegionList::key_type,AudioRegionList::mapped_type> entry;
-
-                               entry.first = region->id();
-                               entry.second = ar;
+               for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
+               
+                       boost::shared_ptr<Region> region = *ii;
+                       
+                       if (region == 0) {
 
-                               pair<AudioRegionList::iterator,bool> x = audio_regions.insert (entry);
+                               error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
 
+                       } else if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
                                
-                               if (!x.second) {
-                                       return;
+                               AudioRegionList::iterator x;
+                               
+                               for (x = audio_regions.begin(); x != audio_regions.end(); ++x) {
+                                       
+                                       oar = boost::dynamic_pointer_cast<AudioRegion> (x->second);
+                                       
+                                       if (ar->region_list_equivalent (oar)) {
+                                               break;
+                                       }
                                }
+                               
+                               if (x == audio_regions.end()) {
+                                       
+                                       pair<AudioRegionList::key_type,AudioRegionList::mapped_type> entry;
+                                       
+                                       entry.first = region->id();
+                                       entry.second = ar;
+                                       
+                                       pair<AudioRegionList::iterator,bool> x = audio_regions.insert (entry);
+                                       
+                                       
+                                       if (!x.second) {
+                                               return;
+                                       }
+                                       
+                                       added = true;
+                               } 
 
-                               added = true;
-                       } 
-
-               } else {
-
-                       fatal << _("programming error: ")
-                             << X_("unknown region type passed to Session::add_region()")
-                             << endmsg;
-                       /*NOTREACHED*/
-
+                       } else {
+                               
+                               fatal << _("programming error: ")
+                                     << X_("unknown region type passed to Session::add_region()")
+                                     << endmsg;
+                               /*NOTREACHED*/
+                               
+                       }
                }
        }
 
@@ -2623,9 +2670,34 @@ Session::add_region (boost::shared_ptr<Region> region)
        set_dirty();
        
        if (added) {
-               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 */
+
+               vector<boost::weak_ptr<AudioRegion> > v;
+               boost::shared_ptr<AudioRegion> first_ar;
+
+               for (vector<boost::shared_ptr<Region> >::iterator ii = new_regions.begin(); ii != new_regions.end(); ++ii) {
+
+                       boost::shared_ptr<Region> region = *ii;
+                       boost::shared_ptr<AudioRegion> ar;
+
+                       if (region == 0) {
+
+                               error << _("Session::add_region() ignored a null region. Warning: you might have lost a region.") << endmsg;
+
+                       } else if ((ar = boost::dynamic_pointer_cast<AudioRegion> (region)) != 0) {
+                               v.push_back (ar);
+
+                               if (!first_ar) {
+                                       first_ar = ar;
+                               }
+                       }
+
+                       region->StateChanged.connect (sigc::bind (mem_fun (*this, &Session::region_changed), boost::weak_ptr<Region>(region)));
+                       region->GoingAway.connect (sigc::bind (mem_fun (*this, &Session::remove_region), boost::weak_ptr<Region>(region)));
+               }
+               
+               if (!v.empty()) {
+                       AudioRegionsAdded (v); /* EMIT SIGNAL */
+               }
        }
 }
 
@@ -2820,6 +2892,9 @@ Session::add_source (boost::shared_ptr<Source> source)
                        set_dirty();
                }
 
+               if (Config->get_auto_analyse_audio()) {
+                       Analyser::queue_source_for_analysis (source, false);
+               }
        } 
 }
 
@@ -3607,18 +3682,36 @@ void
 Session::tempo_map_changed (Change ignored)
 {
        clear_clicks ();
+       
+       for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
+               (*i)->update_after_tempo_map_change ();
+       }
+
+       for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
+               (*i)->update_after_tempo_map_change ();
+       }
+
        set_dirty ();
 }
 
 void
 Session::ensure_passthru_buffers (uint32_t howmany)
 {
+       if (current_block_size == 0) {
+               return;
+       }
+
        while (howmany > _passthru_buffers.size()) {
                Sample *p;
 #ifdef NO_POSIX_MEMALIGN
                p =  (Sample *) malloc(current_block_size * sizeof(Sample));
 #else
-               posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample));
+               if (posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * sizeof(Sample)) != 0) {
+                       fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
+                                                current_block_size, sizeof (Sample), strerror (errno))
+                             << endmsg;
+                       /*NOTREACHED*/
+               }
 #endif                 
                _passthru_buffers.push_back (p);
 
@@ -3627,7 +3720,12 @@ Session::ensure_passthru_buffers (uint32_t howmany)
 #ifdef NO_POSIX_MEMALIGN
                p =  (Sample *) malloc(current_block_size * sizeof(Sample));
 #else
-               posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * 4);
+               if (posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * 4) != 0) {
+                       fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
+                                                current_block_size, sizeof (Sample), strerror (errno))
+                             << endmsg;
+                       /*NOTREACHED*/
+               }
 #endif                 
                memset (p, 0, sizeof (Sample) * current_block_size);
                _silent_buffers.push_back (p);
@@ -4006,9 +4104,37 @@ Session::write_one_audio_track (AudioTrack& track, nframes_t start, nframes_t le
 vector<Sample*>&
 Session::get_silent_buffers (uint32_t howmany)
 {
+       if (howmany > _silent_buffers.size()) {
+
+               error << string_compose (_("Programming error: get_silent_buffers() called for %1 buffers but only %2 exist"),
+                                        howmany, _silent_buffers.size()) << endmsg;
+
+               if (howmany > 1000) {
+                       cerr << "ABSURD: more than 1000 silent buffers requested!\n";
+                       abort ();
+               }
+               
+               while (howmany > _silent_buffers.size()) {
+                       Sample *p = 0;
+                       
+#ifdef NO_POSIX_MEMALIGN
+                       p =  (Sample *) malloc(current_block_size * sizeof(Sample));
+#else
+                       if (posix_memalign((void **)&p,CPU_CACHE_ALIGN,current_block_size * 4) != 0) {
+                               fatal << string_compose (_("Memory allocation error: posix_memalign (%1 * %2) failed (%3)"),
+                                                        current_block_size, sizeof (Sample), strerror (errno))
+                                     << endmsg;
+                               /*NOTREACHED*/
+                       }
+#endif                 
+                       _silent_buffers.push_back (p);
+               }
+       }
+
        for (uint32_t i = 0; i < howmany; ++i) {
                memset (_silent_buffers[i], 0, sizeof (Sample) * current_block_size);
        }
+
        return _silent_buffers;
 }