#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"
, _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 ();
}
sr = atoi (prop->value());
}
}
- }
- if (ensure_engine (sr)) {
- destroy ();
- throw failed_constructor ();
+ if (ensure_engine (sr)) {
+ destroy ();
+ throw failed_constructor ();
+ }
}
if (post_engine_init ()) {
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;
}
/* 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");
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;
}
-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 ();
-
- return 0;
-}
-
void
Session::auto_connect_master_bus ()
{
/* 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) {
offset = current_block_size;
}
- if (synced_to_jack()) {
+ if (synced_to_engine()) {
tf = _engine.transport_frame();
} else {
tf = _transport_frame;
}
}
-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 {
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;
}
}
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;
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.
}
}
- 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;
}
}