transport_sub_state = 0;
_transport_frame = 0;
_requested_return_frame = -1;
- end_location = new Location (0, 0, _("end"), Location::Flags ((Location::IsMark|Location::IsEnd)));
- start_location = new Location (0, 0, _("start"), Location::Flags ((Location::IsMark|Location::IsStart)));
+ _session_range_location = new Location (0, 0, _("session"), Location::IsSessionRange);
g_atomic_int_set (&_record_status, Disabled);
loop_changing = false;
play_loop = false;
have_looped = false;
_last_roll_location = 0;
+ _last_roll_or_reversal_location = 0;
_last_record_location = 0;
pending_locate_frame = 0;
pending_locate_roll = false;
g_atomic_int_set (&_capture_load_min, 100);
_play_range = false;
_exporting = false;
- _gain_automation_buffer = 0;
- _pan_automation_buffer = 0;
- _npan_buffers = 0;
pending_abort = false;
destructive_index = 0;
first_file_data_format_reset = true;
/* These are all static "per-class" signals */
- RegionFactory::CheckNewRegion.connect_same_thread (*this, boost::bind (&Session::add_region, this, _1));
SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
- Processor::ProcessorCreated.connect_same_thread (*this, boost::bind (&Session::add_processor, this, _1));
AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
}
int
-Session::second_stage_init (bool new_session)
+Session::second_stage_init ()
{
AudioFileSource::set_peak_dir (_session_dir->peak_path().to_string());
- if (!new_session) {
+ if (!_is_new) {
if (load_state (_current_snapshot_name)) {
return -1;
}
_engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
try {
- when_engine_running();
+ when_engine_running ();
}
/* handle this one in a different way than all others, so that its clear what happened */
ControlProtocolManager::instance().set_session (this);
- config.set_end_marker_is_free (new_session);
+ config.set_end_marker_is_free (_is_new);
_state_of_the_state = Clean;
}
int
-Session::create (bool& new_session, const string& mix_template, nframes_t initial_length)
+Session::create (const string& mix_template, nframes_t initial_length, BusProfile* bus_profile)
{
if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
return -1;
}
- /* check new_session so we don't overwrite an existing one */
-
if (!mix_template.empty()) {
std::string in_path = mix_template;
if (out){
out << in.rdbuf();
-
- // okay, session is set up. Treat like normal saved
- // session from now on.
-
- new_session = false;
+ _is_new = false;
return 0;
} else {
/* set initial start + end point */
- start_location->set_end (0);
- _locations.add (start_location);
-
- end_location->set_end (initial_length);
- _locations.add (end_location);
+ _session_range_location->set (0, initial_length);
+ _locations.add (_session_range_location);
_state_of_the_state = Clean;
+
+ /* set up Master Out and Control Out if necessary */
- save_state ("");
+ if (bus_profile) {
- return 0;
-}
+ RouteList rl;
+ int control_id = 1;
+ ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
+ if (bus_profile->master_out_channels) {
+ Route* rt = new Route (*this, _("master"), Route::MasterOut, DataType::AUDIO);
+ if (rt->init ()) {
+ delete rt;
+ return -1;
+ }
+ boost_debug_shared_ptr_mark_interesting (rt, "Route");
+ boost::shared_ptr<Route> r (rt);
+ r->input()->ensure_io (count, false, this);
+ r->output()->ensure_io (count, false, this);
+ r->set_remote_control_id (control_id++);
+
+ rl.push_back (r);
+
+ if (Config->get_use_monitor_bus()) {
+ Route* rt = new Route (*this, _("monitor"), Route::MonitorOut, DataType::AUDIO);
+ if (rt->init ()) {
+ delete rt;
+ return -1;
+ }
+ boost_debug_shared_ptr_mark_interesting (rt, "Route");
+ boost::shared_ptr<Route> r (rt);
+ r->input()->ensure_io (count, false, this);
+ r->output()->ensure_io (count, false, this);
+ r->set_remote_control_id (control_id);
+
+ rl.push_back (r);
+ }
-int
-Session::load_diskstreams (const XMLNode& node)
-{
- XMLNodeList clist;
- XMLNodeConstIterator citer;
+ } else {
+ /* prohibit auto-connect to master, because there isn't one */
+ bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
+ }
- clist = node.children();
+ if (!rl.empty()) {
+ add_routes (rl, false);
+ }
- for (citer = clist.begin(); citer != clist.end(); ++citer) {
+ /* this allows the user to override settings with an environment variable.
+ */
- try {
- /* diskstreams added automatically by DiskstreamCreated handler */
- if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
- AudioDiskstream* dsp (new AudioDiskstream (*this, **citer));
- boost::shared_ptr<AudioDiskstream> dstream (dsp);
- add_diskstream (dstream);
- } else if ((*citer)->name() == "MidiDiskstream") {
- boost::shared_ptr<MidiDiskstream> dstream (new MidiDiskstream (*this, **citer));
- add_diskstream (dstream);
- } else {
- error << _("Session: unknown diskstream type in XML") << endmsg;
- }
- }
+ if (no_auto_connect()) {
+ bus_profile->input_ac = AutoConnectOption (0);
+ bus_profile->output_ac = AutoConnectOption (0);
+ }
+
+ Config->set_input_auto_connect (bus_profile->input_ac);
+ Config->set_output_auto_connect (bus_profile->output_ac);
+ }
- catch (failed_constructor& err) {
- error << _("Session: could not load diskstream via XML state") << endmsg;
- return -1;
- }
- }
+ save_state ("");
return 0;
}
sys::remove (xml_path);
}
+#ifdef HAVE_JACK_SESSION
+void
+Session::jack_session_event (jack_session_event_t * event)
+{
+ if (save_state ("jacksession_snap")) {
+ event->flags = JackSessionSaveError;
+ } else {
+ sys::path xml_path (_session_dir->root_path());
+ xml_path /= legalize_for_path ("jacksession_snap") + statefile_suffix;
+
+ string cmd ("PROG_NAME -U ");
+ cmd += event->client_uuid;
+ cmd += " \"";
+ cmd += xml_path.to_string();
+ cmd += '\"';
+
+ event->command_line = strdup (cmd.c_str());
+ }
+
+ jack_session_reply (_engine.jack(), event);
+
+ if (event->type == JackSessionSaveAndQuit) {
+ // TODO: make ardour quit.
+ }
+
+ jack_session_event_free( event );
+}
+#endif
+
int
-Session::save_state (string snapshot_name, bool pending)
+Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot)
{
XMLTree tree;
sys::path xml_path(_session_dir->root_path());
}
if (!_engine.connected ()) {
- error << _("Ardour's audio engine is not connected and state saving would lose all I/O connections. Session not saved")
+ error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
+ PROGRAM_NAME)
<< endmsg;
return 1;
}
if (snapshot_name.empty()) {
snapshot_name = _current_snapshot_name;
- }
+ } else if (switch_to_snapshot) {
+ _current_snapshot_name = snapshot_name;
+ }
if (!pending) {
XMLNode& root (*state_tree->root());
if (root.name() != X_("Session")) {
- error << string_compose (_("Session file %1 is not an Ardour session"), xmlpath.to_string()) << endmsg;
+ error << string_compose (_("Session file %1 is not a session"), xmlpath.to_string()) << endmsg;
delete state_tree;
state_tree = 0;
return -1;
return 0;
}
- info << string_compose (_("Copying old session file %1 to %2\nUse %2 with Ardour versions before 2.0 from now on"),
- xmlpath.to_string(), backup_path.to_string())
+ info << string_compose (_("Copying old session file %1 to %2\nUse %2 with %3 versions before 2.0 from now on"),
+ xmlpath.to_string(), backup_path.to_string(), PROGRAM_NAME)
<< endmsg;
try
if (full_state) {
Glib::Mutex::Lock rl (region_lock);
-#if 0
- for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
-
- /* only store regions not attached to playlists */
-
- if (i->second->playlist() == 0) {
- child->add_child_nocopy (i->second->state (true));
- }
- }
-#else
const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
boost::shared_ptr<Region> r = i->second;
child->add_child_nocopy (r->state (true));
}
}
-#endif
-
- }
-
- child = node->add_child ("DiskStreams");
-
- {
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if (!(*i)->hidden()) {
- child->add_child_nocopy ((*i)->get_state());
- }
- }
}
if (full_state) {
// for a template, just create a new Locations, populate it
// with the default start and end, and get the state for that.
Locations loc;
- Location* start = new Location(0, 0, _("start"), Location::Flags ((Location::IsMark|Location::IsStart)));
- Location* end = new Location(0, 0, _("end"), Location::Flags ((Location::IsMark|Location::IsEnd)));
- start->set_end(0);
- loc.add (start);
- end->set_end(compute_initial_length());
- loc.add (end);
+ Location* range = new Location (0, 0, _("session"), Location::IsSessionRange);
+ range->set (0, compute_initial_length ());
+ loc.add (range);
node->add_child_nocopy (loc.get_state());
}
RouteList public_order (*r);
public_order.sort (cmp);
+ /* the sort should have put control outs first */
+
+ if (_monitor_out) {
+ assert (_monitor_out == public_order.front());
+ }
+
for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
if (!(*i)->is_hidden()) {
if (full_state) {
Locations
Sources
AudioRegions
- AudioDiskstreams
Connections
Routes
RouteGroups
set_auto_punch_location (location);
}
- if ((location = _locations.end_location()) == 0) {
- _locations.add (end_location);
+ if ((location = _locations.session_range_location()) == 0) {
+ _locations.add (_session_range_location);
} else {
- delete end_location;
- end_location = location;
+ delete _session_range_location;
+ _session_range_location = location;
}
- if ((location = _locations.start_location()) == 0) {
- _locations.add (start_location);
- } else {
- delete start_location;
- start_location = location;
- }
-
- AudioFileSource::set_header_position_offset (start_location->start());
+ AudioFileSource::set_header_position_offset (_session_range_location->start());
if ((child = find_named_node (node, "Sources")) == 0) {
error << _("Session: XML state has no sources section") << endmsg;
}
}
- if ((child = find_named_node (node, "DiskStreams")) == 0) {
- error << _("Session: XML state has no diskstreams section") << endmsg;
- goto out;
- } else if (load_diskstreams (*child)) {
- goto out;
- }
-
if (version >= 3000) {
if ((child = find_named_node (node, "Bundles")) == 0) {
warning << _("Session: XML state has no bundles section") << endmsg;
goto out;
}
+ if (version < 3000) {
+ if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
+ error << _("Session: XML state has no diskstreams section") << endmsg;
+ goto out;
+ } else if (load_diskstreams_2X (*child, version)) {
+ goto out;
+ }
+ }
+
if ((child = find_named_node (node, "Routes")) == 0) {
error << _("Session: XML state has no routes section") << endmsg;
goto out;
goto out;
}
+ /* our diskstreams list is no longer needed as they are now all owned by their Route */
+ _diskstreams_2X.clear ();
+
if (version >= 3000) {
if ((child = find_named_node (node, "RouteGroups")) == 0) {
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
- boost::shared_ptr<Route> route (XMLRouteFactory (**niter, version));
-
+ boost::shared_ptr<Route> route;
+ if (version < 3000) {
+ route = XMLRouteFactory_2X (**niter, version);
+ } else {
+ route = XMLRouteFactory (**niter, version);
+ }
+
if (route == 0) {
error << _("Session: cannot create Route from XML description.") << endmsg;
return -1;
boost::shared_ptr<Route>
Session::XMLRouteFactory (const XMLNode& node, int version)
{
+ boost::shared_ptr<Route> ret;
+
if (node.name() != "Route") {
- return boost::shared_ptr<Route> ((Route*) 0);
+ return ret;
}
- bool has_diskstream = (node.property ("diskstream") != 0 || node.property ("diskstream-id") != 0);
+ XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
DataType type = DataType::AUDIO;
const XMLProperty* prop = node.property("default-type");
+
+ if (prop) {
+ type = DataType (prop->value());
+ }
+
+ assert (type != DataType::NIL);
+
+ if (ds_child) {
+
+ Track* track;
+
+ if (type == DataType::AUDIO) {
+ track = new AudioTrack (*this, X_("toBeResetFroXML"));
+
+ } else {
+ track = new MidiTrack (*this, X_("toBeResetFroXML"));
+ }
+
+ if (track->init()) {
+ delete track;
+ return ret;
+ }
+
+ if (track->set_state (node, version)) {
+ delete track;
+ return ret;
+ }
+
+ boost_debug_shared_ptr_mark_interesting (track, "Track");
+ ret.reset (track);
+
+ } else {
+ Route* rt = new Route (*this, X_("toBeResetFroXML"));
+
+ if (rt->init () == 0 && rt->set_state (node, version) == 0) {
+ boost_debug_shared_ptr_mark_interesting (rt, "Route");
+ ret.reset (rt);
+ } else {
+ delete rt;
+ }
+ }
+
+ return ret;
+}
+
+boost::shared_ptr<Route>
+Session::XMLRouteFactory_2X (const XMLNode& node, int version)
+{
boost::shared_ptr<Route> ret;
+ if (node.name() != "Route") {
+ return ret;
+ }
+
+ XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
+ if (!ds_prop) {
+ ds_prop = node.property (X_("diskstream"));
+ }
+
+ DataType type = DataType::AUDIO;
+ const XMLProperty* prop = node.property("default-type");
+
if (prop) {
- type = DataType(prop->value());
+ type = DataType (prop->value());
}
- assert(type != DataType::NIL);
+ assert (type != DataType::NIL);
- if (has_diskstream) {
- if (type == DataType::AUDIO) {
- AudioTrack* at = new AudioTrack (*this, node, version);
- boost_debug_shared_ptr_mark_interesting (at, "Track");
- ret.reset (at);
-
- } else {
- ret.reset (new MidiTrack (*this, node, version));
+ if (ds_prop) {
+
+ list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
+ while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
+ ++i;
}
+
+ if (i == _diskstreams_2X.end()) {
+ error << _("Could not find diskstream for route") << endmsg;
+ return boost::shared_ptr<Route> ();
+ }
+
+ Track* track;
+
+ if (type == DataType::AUDIO) {
+ track = new AudioTrack (*this, X_("toBeResetFroXML"));
+
+ } else {
+ track = new MidiTrack (*this, X_("toBeResetFroXML"));
+ }
+
+ if (track->init()) {
+ delete track;
+ return ret;
+ }
+
+ if (track->set_state (node, version)) {
+ delete track;
+ return ret;
+ }
+
+ track->set_diskstream (*i);
+
+ boost_debug_shared_ptr_mark_interesting (track, "Track");
+ ret.reset (track);
+
} else {
- Route* rt = new Route (*this, node);
- boost_debug_shared_ptr_mark_interesting (rt, "Route");
- ret.reset (rt);
+ Route* rt = new Route (*this, X_("toBeResetFroXML"));
+
+ if (rt->init () == 0 && rt->set_state (node, version) == 0) {
+ boost_debug_shared_ptr_mark_interesting (rt, "Route");
+ ret.reset (rt);
+ } else {
+ delete rt;
+ }
}
return ret;
}
catch (failed_constructor& err) {
- error << _("Found a sound file that cannot be used by Ardour. Talk to the progammers.") << endmsg;
+ error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the progammers."), PROGRAM_NAME) << endmsg;
return boost::shared_ptr<Source>();
}
}
if (str == "master") {
r = _master_out;
} else if (str == "control" || str == "listen") {
- r = _control_out;
+ r = _monitor_out;
} else {
r = route_by_name (desc.top_level_name());
}
if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
/* auto-input only makes a difference if we're rolling */
- boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
-
- for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
- if ((*i)->record_enabled ()) {
- (*i)->monitor_input (!config.get_auto_input());
+ boost::shared_ptr<RouteList> rl = routes.reader ();
+ for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
+ boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
+ if (tr && tr->record_enabled ()) {
+ tr->monitor_input (!config.get_auto_input());
}
}
}
{
_history.set_depth (d);
}
+
+int
+Session::load_diskstreams_2X (XMLNode const & node, int)
+{
+ XMLNodeList clist;
+ XMLNodeConstIterator citer;
+
+ clist = node.children();
+
+ for (citer = clist.begin(); citer != clist.end(); ++citer) {
+
+ try {
+ /* diskstreams added automatically by DiskstreamCreated handler */
+ if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
+ boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
+ _diskstreams_2X.push_back (dsp);
+ } else {
+ error << _("Session: unknown diskstream type in XML") << endmsg;
+ }
+ }
+
+ catch (failed_constructor& err) {
+ error << _("Session: could not load diskstream via XML state") << endmsg;
+ return -1;
+ }
+ }
+
+ return 0;
+}