#include "pbd/pathexpand.h"
#include "pbd/pthread_utils.h"
#include "pbd/stacktrace.h"
-#include "pbd/convert.h"
+#include "pbd/types_convert.h"
#include "pbd/localtime_r.h"
#include "pbd/unwind.h"
#include "ardour/revision.h"
#include "ardour/route_group.h"
#include "ardour/send.h"
+#include "ardour/selection.h"
#include "ardour/session.h"
#include "ardour/session_directory.h"
#include "ardour/session_metadata.h"
#include "ardour/template_utils.h"
#include "ardour/tempo.h"
#include "ardour/ticker.h"
+#include "ardour/types_convert.h"
#include "ardour/user_bundle.h"
#include "ardour/vca.h"
#include "ardour/vca_manager.h"
set_history_depth (Config->get_history_depth());
- /* default: assume simple stereo speaker configuration */
+ /* default: assume simple stereo speaker configuration */
- _speakers->setup_default_speakers (2);
+ _speakers->setup_default_speakers (2);
- _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
- boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
- boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
- add_controllable (_solo_cut_control);
+ _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
+ boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
+ boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
+ add_controllable (_solo_cut_control);
/* These are all static "per-class" signals */
msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
- boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
+ boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
setup_midi_machine_control ();
Config->map_parameters (ff);
config.map_parameters (ft);
- _butler->map_parameters ();
+ _butler->map_parameters ();
/* Reset all panners */
if (Profile->get_trx()) {
/* set initial start + end point : ARDOUR::Session::session_end_shift long.
- Remember that this is a brand new session. Sessions
- loaded from saved state will get this range from the saved state.
- */
+ * Remember that this is a brand new session. Sessions
+ * loaded from saved state will get this range from the saved state.
+ */
set_session_range_location (0, 0);
_state_of_the_state = Clean;
- /* set up Master Out and Monitor Out if necessary */
+ /* set up Master Out and Monitor Out if necessary */
- if (bus_profile) {
+ if (bus_profile) {
RouteList rl;
- ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
+ ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
- // Waves Tracks: always create master bus for Tracks
- if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
- boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
- if (r->init ()) {
- return -1;
- }
+ // Waves Tracks: always create master bus for Tracks
+ if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
+ boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
+ if (r->init ()) {
+ return -1;
+ }
- BOOST_MARK_ROUTE(r);
+ BOOST_MARK_ROUTE(r);
- {
+ {
Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
r->input()->ensure_io (count, false, this);
r->output()->ensure_io (count, false, this);
if (!ARDOUR::Profile->get_trx()) {
/* this allows the user to override settings with an environment variable.
- */
+ */
if (no_auto_connect()) {
bus_profile->input_ac = AutoConnectOption (0);
Config->set_input_auto_connect (bus_profile->input_ac);
Config->set_output_auto_connect (bus_profile->output_ac);
}
- }
+ }
if (Config->get_use_monitor_bus() && bus_profile) {
add_monitor_section ();
void
Session::maybe_write_autosave()
{
- if (dirty() && record_status() != Recording) {
- save_state("", true);
- }
+ if (dirty() && record_status() != Recording) {
+ save_state("", true);
+ }
}
void
_save_queued = false;
if (!_engine.connected ()) {
- error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
- PROGRAM_NAME)
+ 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;
}
/* there is pending state from a crashed capture attempt */
- boost::optional<int> r = AskAboutPendingState();
+ boost::optional<int> r = AskAboutPendingState();
if (r.get_value_or (1)) {
state_was_pending = true;
}
if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
- error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
- return 1;
- }
- }
+ error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
+ return 1;
+ }
+ }
state_tree = new XMLTree;
return -1;
}
- XMLProperty const * prop;
-
- if ((prop = root.property ("version")) == 0) {
- /* no version implies very old version of Ardour */
- Stateful::loading_state_version = 1000;
- } else {
- if (prop->value().find ('.') != string::npos) {
+ std::string version;
+ if (root.get_property ("version", version)) {
+ if (version.find ('.') != string::npos) {
/* old school version format */
- if (prop->value()[0] == '2') {
+ if (version[0] == '2') {
Stateful::loading_state_version = 2000;
} else {
Stateful::loading_state_version = 3000;
}
} else {
- Stateful::loading_state_version = atoi (prop->value());
+ Stateful::loading_state_version = string_to<int32_t>(version);
}
+ } else {
+ /* no version implies very old version of Ardour */
+ Stateful::loading_state_version = 1000;
}
if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
return tree.write (sn.c_str());
}
+namespace
+{
+struct route_id_compare {
+ bool
+ operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
+ {
+ return r1->id () < r2->id ();
+ }
+};
+} // anon namespace
+
XMLNode&
Session::state (bool full_state)
{
XMLNode* node = new XMLNode("Session");
XMLNode* child;
- char buf[16];
- snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
- node->add_property("version", buf);
+ node->set_property("version", CURRENT_SESSION_FILE_VERSION);
child = node->add_child ("ProgramVersion");
- child->add_property("created-with", created_with);
+ child->set_property("created-with", created_with);
std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
- child->add_property("modified-with", modified_with);
+ child->set_property("modified-with", modified_with);
/* store configuration settings */
if (full_state) {
- node->add_property ("name", _name);
- snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
- node->add_property ("sample-rate", buf);
+ node->set_property ("name", _name);
+ node->set_property ("sample-rate", _base_frame_rate);
if (session_dirs.size() > 1) {
child = node->add_child ("Path");
child->add_content (p);
}
+ node->set_property ("end-is-free", _session_range_end_is_free);
}
- node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
-
/* save the ID counter */
- snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
- node->add_property ("id-counter", buf);
+ node->set_property ("id-counter", ID::counter());
- snprintf (buf, sizeof (buf), "%u", name_id_counter ());
- node->add_property ("name-counter", buf);
+ node->set_property ("name-counter", name_id_counter ());
/* save the event ID counter */
- snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
- node->add_property ("event-counter", buf);
+ node->set_property ("event-counter", Evoral::event_id_counter());
/* save the VCA counter */
- snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
- node->add_property ("vca-counter", buf);
+ node->set_property ("vca-counter", VCA::get_next_vca_number());
/* various options */
/* Don't save information about non-file Sources, or
* about non-destructive file sources that are empty
* and unused by any regions.
- */
+ */
boost::shared_ptr<FileSource> fs;
if (full_state) {
Glib::Threads::Mutex::Lock rl (region_lock);
- 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;
- /* only store regions not attached to playlists */
- if (r->playlist() == 0) {
+ 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;
+ /* only store regions not attached to playlists */
+ if (r->playlist() == 0) {
if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
} else {
child->add_child_nocopy (r->get_state ());
}
- }
- }
+ }
+ }
RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
XMLNode* ca = node->add_child (X_("CompoundAssociations"));
for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
- char buf[64];
XMLNode* can = new XMLNode (X_("CompoundAssociation"));
- i->first->id().print (buf, sizeof (buf));
- can->add_property (X_("copy"), buf);
- i->second->id().print (buf, sizeof (buf));
- can->add_property (X_("original"), buf);
+ can->set_property (X_("copy"), i->first->id());
+ can->set_property (X_("original"), i->second->id());
ca->add_child_nocopy (*can);
}
}
}
-
-
if (full_state) {
+ node->add_child_nocopy (_selection->get_state());
+
if (_locations) {
node->add_child_nocopy (_locations->get_state());
}
{
boost::shared_ptr<RouteList> r = routes.reader ();
- RoutePublicOrderSorter cmp;
- RouteList public_order (*r);
- public_order.sort (cmp);
-
- /* the sort should have put the monitor out first */
+ route_id_compare cmp;
+ RouteList xml_node_order (*r);
+ xml_node_order.sort (cmp);
- if (_monitor_out) {
- assert (_monitor_out == public_order.front());
- }
-
- for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
+ for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
if (!(*i)->is_auditioner()) {
if (full_state) {
child->add_child_nocopy ((*i)->get_state());
ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
}
- node->add_child_nocopy (_speakers->get_state());
+ node->add_child_nocopy (_speakers->get_state());
node->add_child_nocopy (_tempo_map->get_state());
node->add_child_nocopy (get_control_protocol_state());
g_free (b64);
XMLNode* script_node = new XMLNode (X_("Script"));
- script_node->add_property (X_("lua"), LUA_VERSION);
+ script_node->set_property (X_("lua"), LUA_VERSION);
script_node->add_content (b64s);
node->add_child_nocopy (*script_node);
}
LocaleGuard lg;
XMLNodeList nlist;
XMLNode* child;
- XMLProperty const * prop;
int ret = -1;
_state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
goto out;
}
- if ((prop = node.property ("name")) != 0) {
- _name = prop->value ();
- }
+ node.get_property ("name", _name);
- if ((prop = node.property (X_("sample-rate"))) != 0) {
+ if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
- _base_frame_rate = atoi (prop->value());
_nominal_frame_rate = _base_frame_rate;
assert (AudioEngine::instance()->running ());
created_with = "unknown";
if ((child = find_named_node (node, "ProgramVersion")) != 0) {
- if ((prop = child->property (X_("created-with"))) != 0) {
- created_with = prop->value ();
- }
+ child->get_property (X_("created-with"), created_with);
}
setup_raid_path(_session_dir->root_path());
- if ((prop = node.property (X_("end-is-free"))) != 0) {
- _session_range_end_is_free = string_is_affirmative (prop->value());
- }
+ node.get_property (X_("end-is-free"), _session_range_end_is_free);
- if ((prop = node.property (X_("id-counter"))) != 0) {
- uint64_t x;
- sscanf (prop->value().c_str(), "%" PRIu64, &x);
- ID::init_counter (x);
+ uint64_t counter;
+ if (node.get_property (X_("id-counter"), counter)) {
+ ID::init_counter (counter);
} else {
/* old sessions used a timebased counter, so fake
- the startup ID counter based on a standard
- timestamp.
- */
+ * the startup ID counter based on a standard
+ * timestamp.
+ */
time_t now;
time (&now);
ID::init_counter (now);
}
- if ((prop = node.property (X_("name-counter"))) != 0) {
- init_name_id_counter (atoi (prop->value()));
+ if (node.get_property (X_("name-counter"), counter)) {
+ init_name_id_counter (counter);
}
- if ((prop = node.property (X_("event-counter"))) != 0) {
- Evoral::init_event_id_counter (atoi (prop->value()));
+ if (node.get_property (X_("event-counter"), counter)) {
+ Evoral::init_event_id_counter (counter);
}
- if ((prop = node.property (X_("vca-counter"))) != 0) {
- uint32_t x;
- sscanf (prop->value().c_str(), "%" PRIu32, &x);
- VCA::set_next_vca_number (x);
+ if (node.get_property (X_("vca-counter"), counter)) {
+ VCA::set_next_vca_number (counter);
} else {
VCA::set_next_vca_number (1);
}
}
}
- if ((child = find_named_node (node, X_("Speakers"))) != 0) {
- _speakers->set_state (*child, version);
- }
+ if ((child = find_named_node (node, X_("Speakers"))) != 0) {
+ _speakers->set_state (*child, version);
+ }
if ((child = find_named_node (node, "Sources")) == 0) {
error << _("Session: XML state has no sources section") << endmsg;
//goto out;
} else {
/* We can't load Bundles yet as they need to be able
- to convert from port names to Port objects, which can't happen until
- later */
+ * to convert from port names to Port objects, which can't happen until
+ * later */
_bundle_xml_node = new XMLNode (*child);
}
}
}
}
+ if ((child = find_named_node (node, X_("Selection")))) {
+ _selection->set_state (*child, version);
+ }
+
update_route_record_state ();
/* here beginneth the second phase ... */
state_tree = 0;
return 0;
- out:
+out:
delete state_tree;
state_tree = 0;
return ret;
XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
DataType type = DataType::AUDIO;
- XMLProperty const * prop = node.property("default-type");
-
- if (prop) {
- type = DataType (prop->value());
- }
+ node.get_property("default-type", type);
assert (type != DataType::NIL);
boost::shared_ptr<Track> track;
- if (type == DataType::AUDIO) {
- track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
- } else {
- track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
- }
+ if (type == DataType::AUDIO) {
+ track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
+ } else {
+ track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
+ }
- if (track->init()) {
- return ret;
- }
+ if (track->init()) {
+ return ret;
+ }
- if (track->set_state (node, version)) {
- return ret;
- }
+ if (track->set_state (node, version)) {
+ return ret;
+ }
- BOOST_MARK_TRACK (track);
- ret = track;
+ BOOST_MARK_TRACK (track);
+ ret = track;
} else {
PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
- if (r->init () == 0 && r->set_state (node, version) == 0) {
- BOOST_MARK_ROUTE (r);
- ret = r;
- }
+ if (r->init () == 0 && r->set_state (node, version) == 0) {
+ BOOST_MARK_ROUTE (r);
+ ret = r;
+ }
}
return ret;
}
DataType type = DataType::AUDIO;
- XMLProperty const * prop = node.property("default-type");
-
- if (prop) {
- type = DataType (prop->value());
- }
+ node.get_property("default-type", type);
assert (type != DataType::NIL);
boost::shared_ptr<Track> track;
- if (type == DataType::AUDIO) {
- track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
- } else {
- track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
- }
+ if (type == DataType::AUDIO) {
+ track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
+ } else {
+ track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
+ }
- if (track->init()) {
- return ret;
- }
+ if (track->init()) {
+ return ret;
+ }
- if (track->set_state (node, version)) {
- return ret;
- }
+ if (track->set_state (node, version)) {
+ return ret;
+ }
track->set_diskstream (*i);
BOOST_MARK_TRACK (track);
- ret = track;
+ ret = track;
} else {
PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
- if (r->init () == 0 && r->set_state (node, version) == 0) {
- BOOST_MARK_ROUTE (r);
- ret = r;
- }
+ if (r->init () == 0 && r->set_state (node, version) == 0) {
+ BOOST_MARK_ROUTE (r);
+ ret = r;
+ }
}
return ret;
}
}
- if (!type || type->value() == "audio") {
- return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
- } else if (type->value() == "midi") {
- return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
- }
+ if (!type || type->value() == "audio") {
+ return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
+ } else if (type->value() == "midi") {
+ return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
+ }
} catch (failed_constructor& err) {
return boost::shared_ptr<Region> ();
return boost::shared_ptr<AudioRegion>();
}
- if ((prop = node.property (X_("channels"))) != 0) {
- nchans = atoi (prop->value().c_str());
- }
+ node.get_property (X_("channels"), nchans);
if ((prop = node.property ("name")) == 0) {
cerr << "no name for this region\n";
{
XMLNodeList nlist;
XMLNodeConstIterator niter;
- boost::shared_ptr<Source> source; /* don't need this but it stops some
- * versions of gcc complaining about
- * discarded return values.
- */
+ /* don't need this but it stops some
+ * versions of gcc complaining about
+ * discarded return values.
+ */
+ boost::shared_ptr<Source> source;
nlist = node.children();
set_dirty();
+ std::map<std::string, std::string> relocation;
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
#ifdef PLATFORM_WINDOWS
int old_mode = 0;
#endif
- retry:
+ XMLNode srcnode (**niter);
+ bool try_replace_abspath = true;
+
+retry:
try {
#ifdef PLATFORM_WINDOWS
// do not show "insert media" popups (files embedded from removable media).
old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
#endif
- if ((source = XMLSourceFactory (**niter)) == 0) {
+ if ((source = XMLSourceFactory (srcnode)) == 0) {
error << _("Session: cannot create Source from XML description.") << endmsg;
}
#ifdef PLATFORM_WINDOWS
SetErrorMode(old_mode);
#endif
- int user_choice;
+ /* try previous abs path replacements first */
+ if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
+ std::string dir = Glib::path_get_dirname (err.path);
+ std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
+ if (rl != relocation.end ()) {
+ std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
+ if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
+ srcnode.set_property ("origin", newpath);
+ try_replace_abspath = false;
+ goto retry;
+ }
+ }
+ }
+
+ int user_choice;
+ _missing_file_replacement = "";
if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
- error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
- PROGRAM_NAME) << endmsg;
+ error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
+ PROGRAM_NAME) << endmsg;
return -1;
}
- if (!no_questions_about_missing_files) {
+ if (!no_questions_about_missing_files) {
user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
} else {
- user_choice = -2;
- }
+ user_choice = -2;
+ }
- switch (user_choice) {
- case 0:
- /* user added a new search location, so try again */
- goto retry;
+ switch (user_choice) {
+ case 0:
+ /* user added a new search location
+ * or selected a new absolute path,
+ * so try again */
+ if (Glib::path_is_absolute (err.path)) {
+ if (!_missing_file_replacement.empty ()) {
+ /* replace origin, in XML */
+ std::string newpath = Glib::build_filename (
+ _missing_file_replacement, Glib::path_get_basename (err.path));
+ srcnode.set_property ("origin", newpath);
+ relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
+ _missing_file_replacement = "";
+ }
+ }
+ goto retry;
- case 1:
- /* user asked to quit the entire session load
- */
- return -1;
+ case 1:
+ /* user asked to quit the entire session load */
+ return -1;
- case 2:
- no_questions_about_missing_files = true;
- goto retry;
+ case 2:
+ no_questions_about_missing_files = true;
+ goto retry;
- case 3:
- no_questions_about_missing_files = true;
- /* fallthru */
+ case 3:
+ no_questions_about_missing_files = true;
+ /* fallthru */
- case -1:
- default:
- switch (err.type) {
+ case -1:
+ default:
+ switch (err.type) {
- case DataType::AUDIO:
- source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
- break;
+ case DataType::AUDIO:
+ source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
+ break;
- case DataType::MIDI:
- /* The MIDI file is actually missing so
- * just create a new one in the same
- * location. Do not announce its
- */
- string fullpath;
-
- if (!Glib::path_is_absolute (err.path)) {
- fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
- } else {
- /* this should be an unrecoverable error: we would be creating a MIDI file outside
- the session tree.
- */
- return -1;
+ case DataType::MIDI:
+ /* The MIDI file is actually missing so
+ * just create a new one in the same
+ * location. Do not announce its
+ */
+ string fullpath;
+
+ if (!Glib::path_is_absolute (err.path)) {
+ fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
+ } else {
+ /* this should be an unrecoverable error: we would be creating a MIDI file outside
+ * the session tree.
+ */
+ return -1;
+ }
+ /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
+ source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
+ /* reset ID to match the missing one */
+ source->set_id (**niter);
+ /* Now we can announce it */
+ SourceFactory::SourceCreated (source);
+ break;
}
- /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
- source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
- /* reset ID to match the missing one */
- source->set_id (**niter);
- /* Now we can announce it */
- SourceFactory::SourceCreated (source);
break;
- }
- break;
- }
+ }
}
}
vector<string> scanned_volumes;
vector<string>::iterator j;
vector<space_and_path>::iterator i;
- DWORD nSectorsPerCluster, nBytesPerSector,
- nFreeClusters, nTotalClusters;
- char disk_drive[4];
+ DWORD nSectorsPerCluster, nBytesPerSector,
+ nFreeClusters, nTotalClusters;
+ char disk_drive[4];
bool volume_found;
_total_free_4k_blocks = 0;
RouteGroup&
Session::all_route_group() const
{
- return *_all_route_group;
+ return *_all_route_group;
}
void
static bool
accept_all_audio_files (const string& path, void* /*arg*/)
{
- if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
- return false;
- }
+ if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
+ return false;
+ }
- if (!AudioFileSource::safe_audio_file_extension (path)) {
- return false;
- }
+ if (!AudioFileSource::safe_audio_file_extension (path)) {
+ return false;
+ }
- return true;
+ return true;
}
static bool
accept_all_midi_files (const string& path, void* /*arg*/)
{
- if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
- return false;
- }
+ if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
+ return false;
+ }
- return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
- (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
- (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
+ return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
+ || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
+ || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
}
static bool
}
struct RegionCounter {
- typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
- AudioSourceList::iterator iter;
- boost::shared_ptr<Region> region;
- uint32_t count;
+ typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
+ AudioSourceList::iterator iter;
+ boost::shared_ptr<Region> region;
+ uint32_t count;
- RegionCounter() : count (0) {}
+ RegionCounter() : count (0) {}
};
int
Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
{
- boost::optional<int> r = AskAboutPlaylistDeletion (p);
+ boost::optional<int> r = AskAboutPlaylistDeletion (p);
return r.get_value_or (1);
}
warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
return false;
}
- if (record_status() == Recording) {
+ if (record_status() == Recording) {
error << _("Cannot cleanup peak-files while recording") << endmsg;
return false;
}
goto out;
}
- /* sync the "all regions" property of each playlist with its current state
- */
+ /* sync the "all regions" property of each playlist with its current state */
- playlists->sync_all_regions_with_regions ();
+ playlists->sync_all_regions_with_regions ();
/* find all un-used sources */
++tmp;
/* do not bother with files that are zero size, otherwise we remove the current "nascent"
- capture files.
- */
+ * capture files.
+ */
if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
dead_sources.push_back (i->second);
find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
/* add sources from all other snapshots as "used", but don't use this
- snapshot because the state file on disk still references sources we
- may have already dropped.
- */
+ snapshot because the state file on disk still references sources we
+ may have already dropped.
+ */
find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
/* add our current source list
- */
+ */
for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
boost::shared_ptr<FileSource> fs;
- SourceMap::iterator tmp = i;
- ++tmp;
+ SourceMap::iterator tmp = i;
+ ++tmp;
if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
/* not a file */
cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
} else {
cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
- /* this source is NOT in use by this snapshot
- */
+ /* this source is NOT in use by this snapshot */
- /* remove all related regions from RegionFactory master list
- */
+ /* remove all related regions from RegionFactory master list */
RegionFactory::remove_regions_using_source (i->second);
}
}
- i = tmp;
+ i = tmp;
}
/* now check each candidate source to see if it exists in the list of
- sources_used_by_all_snapshots. If it doesn't, put it into "unused".
- */
+ * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
+ */
cerr << "Candidates: " << candidates.size() << endl;
cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
string newpath;
/* don't move the file across filesystems, just
- stick it in the `dead_dir_name' directory
- on whichever filesystem it was already on.
- */
+ * stick it in the `dead_dir_name' directory
+ * on whichever filesystem it was already on.
+ */
if ((*x).find ("/sounds/") != string::npos) {
if (version == 999) {
error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
- newpath)
- << endmsg;
+ newpath)
+ << endmsg;
} else {
newpath = newpath_v;
}
if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
- newpath, g_strerror (errno)) << endmsg;
+ newpath, g_strerror (errno)) << endmsg;
continue;
}
- /* see if there an easy to find peakfile for this file, and remove it.
- */
+ /* see if there an easy to find peakfile for this file, and remove it. */
string base = Glib::path_get_basename (*x);
base += "%A"; /* this is what we add for the channel suffix of all native files,
- or for the first channel of embedded files. it will miss
- some peakfiles for other channels
- */
+ * or for the first channel of embedded files. it will miss
+ * some peakfiles for other channels
+ */
string peakpath = construct_peak_filepath (base);
if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
if (::g_unlink (peakpath.c_str ()) != 0) {
error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
- g_strerror (errno)) << endmsg;
+ g_strerror (errno)) << endmsg;
/* try to back out */
::g_rename (newpath.c_str (), _path.c_str ());
goto out;
_history.clear ();
/* save state so we don't end up a session file
- referring to non-existent sources.
- */
+ * referring to non-existent sources.
+ */
save_state ("");
ret = 0;
- out:
+out:
_state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
return ret;
dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
- clear_directory (dead_dir, &rep.space, &rep.paths);
+ clear_directory (dead_dir, &rep.space, &rep.paths);
}
return 0;
void
Session::set_dirty ()
{
- /* never mark session dirty during loading */
+ /* return early if there's nothing to do */
+ if (dirty ()) {
+ return;
+ }
+ /* never mark session dirty during loading */
if (_state_of_the_state & Loading) {
return;
}
- bool was_dirty = dirty();
-
_state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
-
-
- if (!was_dirty) {
- DirtyChanged(); /* EMIT SIGNAL */
- }
+ DirtyChanged(); /* EMIT SIGNAL */
}
-
void
Session::set_clean ()
{
_state_of_the_state = Clean;
-
if (was_dirty) {
DirtyChanged(); /* EMIT SIGNAL */
}
return boost::shared_ptr<Controllable>();
}
+boost::shared_ptr<AutomationControl>
+Session::automation_control_by_id (const PBD::ID& id)
+{
+ return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
+}
+
boost::shared_ptr<Controllable>
Session::controllable_by_descriptor (const ControllableDescriptor& desc)
{
break;
case ControllableDescriptor::Solo:
- c = s->solo_control();
+ c = s->solo_control();
break;
case ControllableDescriptor::Mute:
XMLNode *t = *it;
UndoTransaction* ut = new UndoTransaction ();
- struct timeval tv;
- ut->set_name(t->property("name")->value());
- stringstream ss(t->property("tv-sec")->value());
- ss >> tv.tv_sec;
- ss.str(t->property("tv-usec")->value());
- ss >> tv.tv_usec;
+ std::string name;
+ int64_t tv_sec;
+ int64_t tv_usec;
+
+ if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
+ !t->get_property ("tv-usec", tv_usec)) {
+ continue;
+ }
+
+ ut->set_name (name);
+
+ struct timeval tv;
+ tv.tv_sec = tv_sec;
+ tv.tv_usec = tv_usec;
ut->set_timestamp(tv);
for (XMLNodeConstIterator child_it = t->children().begin();
_clicking = false;
}
+ } else if (p == "click-record-only") {
+
+ _click_rec_only = Config->get_click_record_only();
+
} else if (p == "click-gain") {
if (_click_gain) {
int
Session::load_diskstreams_2X (XMLNode const & node, int)
{
- XMLNodeList clist;
- XMLNodeConstIterator citer;
+ XMLNodeList clist;
+ XMLNodeConstIterator citer;
- clist = node.children();
+ clist = node.children();
- for (citer = clist.begin(); citer != clist.end(); ++citer) {
+ for (citer = clist.begin(); citer != clist.end(); ++citer) {
- try {
- /* diskstreams added automatically by DiskstreamCreated handler */
- if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
+ 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;
+ } 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;
}
/** Connect things to the MMC object */
boost::shared_ptr<Controllable>
Session::solo_cut_control() const
{
- /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
- controls in Ardour that currently get presented to the user in the GUI that require
- access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
-
- its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
- it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
- parameter.
- */
-
- return _solo_cut_control;
+ /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
+ * controls in Ardour that currently get presented to the user in the GUI that require
+ * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
+ *
+ * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
+ * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
+ * parameter.
+ */
+ return _solo_cut_control;
}
void
instant_xml ("LastUsedSnapshot");
XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
- last_used_snapshot->add_property ("name", string(n));
+ last_used_snapshot->set_property ("name", n);
add_instant_xml (*last_used_snapshot, false);
}
error << _("Cannot rename read-only session.") << endmsg;
return 0; // don't show "messed up" warning
}
- if (record_status() == Recording) {
+ if (record_status() == Recording) {
error << _("Cannot rename session while recording") << endmsg;
return 0; // don't show "messed up" warning
}
if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
cerr << string_compose (_("renaming %s as %2 failed (%3)"),
- old_interchange_dir, new_interchange_dir,
- g_strerror (errno))
- << endl;
+ old_interchange_dir, new_interchange_dir,
+ g_strerror (errno))
+ << endl;
error << string_compose (_("renaming %s as %2 failed (%3)"),
- old_interchange_dir, new_interchange_dir,
- g_strerror (errno))
+ old_interchange_dir, new_interchange_dir,
+ g_strerror (errno))
<< endmsg;
return 1;
}
}
}
-
_path = to_dir;
set_snapshot_name (saveas.new_name);
_name = saveas.new_name;
bool was_dirty = dirty ();
- save_state ("", false, false, !saveas.include_media);
save_default_options ();
if (saveas.copy_media && saveas.copy_external) {
if (!saveas.switch_to) {
+ /* save the new state */
+
+ save_state ("", false, false, !saveas.include_media);
+
/* switch back to the way things were */
_path = old_path;
session_dirs.push_back (sp);
refresh_disk_space ();
+ _writable = exists_and_writable (_path);
+
/* ensure that all existing tracks reset their current capture source paths
*/
reset_write_sources (true, true);
+ /* creating new write sources marks the session as
+ dirty. If the new session is empty, then
+ save_state() thinks we're saving a template and will
+ not mark the session as clean. So do that here,
+ before we save state.
+ */
+
+ if (!saveas.include_media) {
+ _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
+ }
+
+ save_state ("", false, false, !saveas.include_media);
+
/* the copying above was based on actually discovering files, not just iterating over the sources list.
But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
*/