Merge branch 'master' into windows+cc
[ardour.git] / libs / ardour / session.cc
index 9934d5a095f38366f9f09909c0eebdb5645fad18..4b30543cb018021dfd904314d89819926b4a194f 100644 (file)
@@ -44,8 +44,8 @@
 #include "pbd/stacktrace.h"
 #include "pbd/file_utils.h"
 #include "pbd/convert.h"
-#include "pbd/strsplit.h"
 #include "pbd/unwind.h"
+#include "pbd/search_path.h"
 
 #include "ardour/amp.h"
 #include "ardour/analyser.h"
@@ -258,17 +258,41 @@ Session::Session (AudioEngine &eng,
        , _suspend_timecode_transmission (0)
        ,  _speakers (new Speakers)
        , ignore_route_processor_changes (false)
+       , _midi_ports (0)
+       , _mmc (0)
 {
        uint32_t sr = 0;
 
        pre_engine_init (fullpath);
        
        if (_is_new) {
+               if (ensure_engine (sr)) {
+                       destroy ();
+                       throw failed_constructor ();
+               }
+
                if (create (mix_template, bus_profile)) {
                        destroy ();
                        throw failed_constructor ();
                }
+
+               /* if a mix template was provided, then ::create() will
+                * have copied it into the session and we need to load it
+                * so that we have the state ready for ::set_state()
+                * after the engine is started.
+                *
+                * Note that we do NOT try to get the sample rate from
+                * the template at this time, though doing so would
+                * be easy if we decided this was an appropriate part
+                * of a template.
+                */
+
+               if (!mix_template.empty() && load_state (_current_snapshot_name)) {
+                       throw failed_constructor ();
+               }
+
        } else {
+
                if (load_state (_current_snapshot_name)) {
                        throw failed_constructor ();
                }
@@ -284,26 +308,13 @@ Session::Session (AudioEngine &eng,
                                sr = atoi (prop->value());
                        }
                }
-       }
-       
-       if (_engine.current_backend() == 0 || _engine.setup_required()) {
-               boost::optional<int> r = AudioEngineSetupRequired (sr);
-               if (r.get_value_or (-1) != 0) {
+
+               if (ensure_engine (sr)) {
                        destroy ();
-                       throw failed_constructor();
+                       throw failed_constructor ();
                }
        }
 
-       /* at this point the engine should be connected (i.e. interacting
-          with a backend device (or psuedo-device) and available to us
-          for determinining sample rates and other settings.
-       */
-
-       if (!_engine.connected()) {
-               destroy ();
-               throw failed_constructor();
-       }
-
        if (post_engine_init ()) {
                destroy ();
                throw failed_constructor ();
@@ -326,6 +337,16 @@ Session::Session (AudioEngine &eng,
        EndTimeChanged.connect_same_thread (*this, boost::bind (&Session::end_time_changed, this, _1));
 
        _is_new = false;
+
+       /* hook us up to the engine since we are now completely constructed */
+
+       BootMessage (_("Connect to engine"));
+
+       _engine.set_session (this);
+       _engine.reset_timebase ();
+
+       BootMessage (_("Session loading complete"));
+
 }
 
 Session::~Session ()
@@ -336,6 +357,81 @@ Session::~Session ()
        destroy ();
 }
 
+int
+Session::ensure_engine (uint32_t desired_sample_rate)
+{
+       if (_engine.current_backend() == 0) {
+               /* backend is unknown ... */
+               boost::optional<int> r = AudioEngineSetupRequired (desired_sample_rate);
+               if (r.get_value_or (-1) != 0) {
+                       return -1;
+               }
+       } else if (_engine.setup_required()) {
+               /* backend is known, but setup is needed */
+               boost::optional<int> r = AudioEngineSetupRequired (desired_sample_rate);
+               if (r.get_value_or (-1) != 0) {
+                       return -1;
+               }
+       } else if (!_engine.running()) {
+               if (_engine.start()) {
+                       return -1;
+               }
+       }
+
+       /* at this point the engine should be running
+       */
+
+       if (!_engine.running()) {
+               return -1;
+       }
+
+       return immediately_post_engine ();
+
+}
+
+int
+Session::immediately_post_engine ()
+{
+       /* Do various initializations that should take place directly after we
+        * know that the engine is running, but before we either create a
+        * session or set state for an existing one.
+        */
+        
+       if (how_many_dsp_threads () > 1) {
+               /* For now, only create the graph if we are using >1 DSP threads, as
+                  it is a bit slower than the old code with 1 thread.
+               */
+               _process_graph.reset (new Graph (*this));
+       }
+
+       /* every time we reconnect, recompute worst case output latencies */
+
+       _engine.Running.connect_same_thread (*this, boost::bind (&Session::initialize_latencies, this));
+
+       if (synced_to_engine()) {
+               _engine.transport_stop ();
+       }
+
+       if (config.get_jack_time_master()) {
+               _engine.transport_locate (_transport_frame);
+       }
+
+       try {
+               BootMessage (_("Set up LTC"));
+               setup_ltc ();
+               BootMessage (_("Set up Click"));
+               setup_click ();
+               BootMessage (_("Set up standard connections"));
+               setup_bundles ();
+       }
+
+       catch (failed_constructor& err) {
+               return -1;
+       }
+
+       return 0;
+}
+
 void
 Session::destroy ()
 {
@@ -446,9 +542,9 @@ Session::destroy ()
        /* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
        playlists.reset ();
 
-       delete _mmc;
-       delete _midi_ports;
-       delete _locations;
+       delete _mmc; _mmc = 0;
+       delete _midi_ports; _midi_ports = 0;
+       delete _locations; _locations = 0;
 
        DEBUG_TRACE (DEBUG::Destruction, "Session::destroy() done\n");
 
@@ -496,14 +592,21 @@ Session::setup_ltc ()
 void
 Session::setup_click ()
 {
-       XMLNode* child = 0;
-
        _clicking = false;
        _click_io.reset (new ClickIO (*this, "click"));
        _click_gain.reset (new Amp (*this));
        _click_gain->activate ();
-       
-       if (state_tree && (child = find_named_node (*state_tree->root(), "Click")) != 0) {
+       if (state_tree) {
+               setup_click_state (*state_tree->root());
+       }
+}
+
+void
+Session::setup_click_state (const XMLNode& node)
+{      
+       const XMLNode* child = 0;
+
+       if ((child = find_named_node (node, "Click")) != 0) {
                
                /* existing state for Click */
                int c = 0;
@@ -655,87 +758,6 @@ Session::setup_bundles ()
 
 }
 
-int
-Session::when_engine_running ()
-{
-       /* every time we reconnect, recompute worst case output latencies */
-
-       _engine.Running.connect_same_thread (*this, boost::bind (&Session::initialize_latencies, this));
-
-       if (synced_to_jack()) {
-               _engine.transport_stop ();
-       }
-
-       if (config.get_jack_time_master()) {
-               _engine.transport_locate (_transport_frame);
-       }
-
-
-       try {
-               BootMessage (_("Set up LTC"));
-               setup_ltc ();
-               BootMessage (_("Set up Click"));
-               setup_click ();
-               BootMessage (_("Set up standard connections"));
-               setup_bundles ();
-       }
-
-       catch (failed_constructor& err) {
-               return -1;
-       }
-
-       BootMessage (_("Setup signal flow and plugins"));
-
-       /* Reset all panners */
-
-       Delivery::reset_panners ();
-
-       /* this will cause the CPM to instantiate any protocols that are in use
-        * (or mandatory), which will pass it this Session, and then call
-        * set_state() on each instantiated protocol to match stored state.
-        */
-
-       ControlProtocolManager::instance().set_session (this);
-
-       /* This must be done after the ControlProtocolManager set_session above,
-          as it will set states for ports which the ControlProtocolManager creates.
-       */
-
-       // XXX set state of MIDI::Port's
-       // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
-
-       /* And this must be done after the MIDI::Manager::set_port_states as
-        * it will try to make connections whose details are loaded by set_port_states.
-        */
-
-       hookup_io ();
-
-       /* Let control protocols know that we are now all connected, so they
-        * could start talking to surfaces if they want to.
-        */
-
-       ControlProtocolManager::instance().midi_connectivity_established ();
-
-       if (_is_new && !no_auto_connect()) {
-               Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
-               auto_connect_master_bus ();
-       }
-
-       _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
-
-        /* update latencies */
-
-        initialize_latencies ();
-
-       /* hook us up to the engine */
-
-       BootMessage (_("Connect to engine"));
-       _engine.set_session (this);
-       _engine.reset_timebase ();
-
-       return 0;
-}
-
 void
 Session::auto_connect_master_bus ()
 {
@@ -895,14 +917,14 @@ Session::add_monitor_section ()
                        
                        /* Monitor bus is audio only */
 
-                       uint32_t mod = n_physical_outputs.get (DataType::AUDIO);
-                       uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
                        vector<string> outputs[DataType::num_types];
 
                        for (uint32_t i = 0; i < DataType::num_types; ++i) {
                                _engine.get_physical_outputs (DataType (DataType::Symbol (i)), outputs[i]);
                        }
-                       
+
+                       uint32_t mod = outputs[DataType::AUDIO].size();
+                       uint32_t limit = _monitor_out->n_outputs().get (DataType::AUDIO);
                        
                        if (mod != 0) {
                                
@@ -1406,7 +1428,7 @@ Session::audible_frame () const
                offset = current_block_size;
        }
 
-       if (synced_to_jack()) {
+       if (synced_to_engine()) {
                tf = _engine.transport_frame();
        } else {
                tf = _transport_frame;
@@ -1466,6 +1488,7 @@ Session::set_frame_rate (framecnt_t frames_per_second)
        */
 
        _base_frame_rate = frames_per_second;
+       _nominal_frame_rate = frames_per_second;
 
        sync_time_vars();
 
@@ -4552,18 +4575,18 @@ Session::end_time_changed (framepos_t old)
        }
 }
 
-string
+std::vector<std::string>
 Session::source_search_path (DataType type) const
 {
-       vector<string> s;
+       Searchpath sp;
 
        if (session_dirs.size() == 1) {
                switch (type) {
                case DataType::AUDIO:
-                       s.push_back (_session_dir->sound_path());
+                       sp.push_back (_session_dir->sound_path());
                        break;
                case DataType::MIDI:
-                       s.push_back (_session_dir->midi_path());
+                       sp.push_back (_session_dir->midi_path());
                        break;
                }
        } else {
@@ -4571,10 +4594,10 @@ Session::source_search_path (DataType type) const
                        SessionDirectory sdir (i->path);
                        switch (type) {
                        case DataType::AUDIO:
-                               s.push_back (sdir.sound_path());
+                               sp.push_back (sdir.sound_path());
                                break;
                        case DataType::MIDI:
-                               s.push_back (sdir.midi_path());
+                               sp.push_back (sdir.midi_path());
                                break;
                        }
                }
@@ -4583,49 +4606,30 @@ Session::source_search_path (DataType type) const
        if (type == DataType::AUDIO) {
                const string sound_path_2X = _session_dir->sound_path_2X();
                if (Glib::file_test (sound_path_2X, Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_DIR)) {
-                       if (find (s.begin(), s.end(), sound_path_2X) == s.end()) {
-                               s.push_back (sound_path_2X);
+                       if (find (sp.begin(), sp.end(), sound_path_2X) == sp.end()) {
+                               sp.push_back (sound_path_2X);
                        }
                }
        }
 
-       /* now check the explicit (possibly user-specified) search path
-        */
-
-       vector<string> dirs;
+       // now check the explicit (possibly user-specified) search path
 
        switch (type) {
        case DataType::AUDIO:
-               split (config.get_audio_search_path (), dirs, ':');
+               sp += Searchpath(config.get_audio_search_path ());
                break;
        case DataType::MIDI:
-               split (config.get_midi_search_path (), dirs, ':');
+               sp += Searchpath(config.get_midi_search_path ());
                break;
        }
 
-       for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
-               if (find (s.begin(), s.end(), *i) == s.end()) {
-                       s.push_back (*i);
-               }
-       }
-       
-       string search_path;
-
-       for (vector<string>::iterator si = s.begin(); si != s.end(); ++si) {
-               if (!search_path.empty()) {
-                       search_path += ':';
-               }
-               search_path += *si;
-       }
-
-       return search_path;
+       return sp;
 }
 
 void
 Session::ensure_search_path_includes (const string& path, DataType type)
 {
-       string search_path;
-       vector<string> dirs;
+       Searchpath sp;
 
        if (path == ".") {
                return;
@@ -4633,16 +4637,14 @@ Session::ensure_search_path_includes (const string& path, DataType type)
 
        switch (type) {
        case DataType::AUDIO:
-               search_path = config.get_audio_search_path ();
+               sp += Searchpath(config.get_audio_search_path ());
                break;
        case DataType::MIDI:
-               search_path = config.get_midi_search_path ();
+               sp += Searchpath (config.get_midi_search_path ());
                break;
        }
 
-       split (search_path, dirs, ':');
-
-       for (vector<string>::iterator i = dirs.begin(); i != dirs.end(); ++i) {
+       for (vector<std::string>::iterator i = sp.begin(); i != sp.end(); ++i) {
                /* No need to add this new directory if it has the same inode as
                   an existing one; checking inode rather than name prevents duplicated
                   directories when we are using symlinks.
@@ -4654,18 +4656,14 @@ Session::ensure_search_path_includes (const string& path, DataType type)
                }
        }
 
-       if (!search_path.empty()) {
-               search_path += ':';
-       }
-
-       search_path += path;
+       sp += path;
 
        switch (type) {
        case DataType::AUDIO:
-               config.set_audio_search_path (search_path);
+               config.set_audio_search_path (sp.to_string());
                break;
        case DataType::MIDI:
-               config.set_midi_search_path (search_path);
+               config.set_midi_search_path (sp.to_string());
                break;
        }
 }