2 Copyright (C) 1999-2002 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 #define __STDC_FORMAT_MACROS 1
28 #include <sigc++/bind.h>
30 #include <cstdio> /* snprintf(3) ... grrr */
45 #include <sys/param.h>
46 #include <sys/mount.h>
50 #include <glibmm/thread.h>
52 #include "midi++/mmc.h"
53 #include "midi++/port.h"
55 #include "pbd/error.h"
56 #include "pbd/pathscanner.h"
57 #include "pbd/pthread_utils.h"
58 #include "pbd/search_path.h"
59 #include "pbd/stacktrace.h"
61 #include "ardour/audioengine.h"
62 #include "ardour/configuration.h"
63 #include "ardour/session.h"
64 #include "ardour/session_directory.h"
65 #include "ardour/session_utils.h"
66 #include "ardour/session_state_utils.h"
67 #include "ardour/session_metadata.h"
68 #include "ardour/buffer.h"
69 #include "ardour/audio_diskstream.h"
70 #include "ardour/midi_diskstream.h"
71 #include "ardour/utils.h"
72 #include "ardour/audioplaylist.h"
73 #include "ardour/midi_playlist.h"
74 #include "ardour/smf_source.h"
75 #include "ardour/audiofilesource.h"
76 #include "ardour/silentfilesource.h"
77 #include "ardour/sndfilesource.h"
78 #include "ardour/midi_source.h"
79 #include "ardour/sndfile_helpers.h"
80 #include "ardour/auditioner.h"
81 #include "ardour/io_processor.h"
82 #include "ardour/send.h"
83 #include "ardour/processor.h"
84 #include "ardour/user_bundle.h"
85 #include "ardour/slave.h"
86 #include "ardour/tempo.h"
87 #include "ardour/audio_track.h"
88 #include "ardour/midi_track.h"
89 #include "ardour/midi_patch_manager.h"
90 #include "ardour/cycle_timer.h"
91 #include "ardour/utils.h"
92 #include "ardour/named_selection.h"
93 #include "ardour/version.h"
94 #include "ardour/location.h"
95 #include "ardour/audioregion.h"
96 #include "ardour/midi_region.h"
97 #include "ardour/crossfade.h"
98 #include "ardour/control_protocol_manager.h"
99 #include "ardour/region_factory.h"
100 #include "ardour/source_factory.h"
101 #include "ardour/playlist_factory.h"
102 #include "ardour/filename_extensions.h"
103 #include "ardour/directory_names.h"
104 #include "ardour/template_utils.h"
105 #include "ardour/ticker.h"
106 #include "ardour/route_group.h"
108 #include "control_protocol/control_protocol.h"
114 using namespace ARDOUR;
118 Session::first_stage_init (string fullpath, string snapshot_name)
120 if (fullpath.length() == 0) {
122 throw failed_constructor();
125 char buf[PATH_MAX+1];
126 if (!realpath (fullpath.c_str(), buf) && (errno != ENOENT)) {
127 error << string_compose(_("Could not use path %1 (%s)"), buf, strerror(errno)) << endmsg;
129 throw failed_constructor();
134 if (_path[_path.length()-1] != '/') {
138 /* these two are just provisional settings. set_state()
139 will likely override them.
142 _name = _current_snapshot_name = snapshot_name;
144 set_history_depth (Config->get_history_depth());
146 _current_frame_rate = _engine.frame_rate ();
147 _nominal_frame_rate = _current_frame_rate;
148 _base_frame_rate = _current_frame_rate;
150 _tempo_map = new TempoMap (_current_frame_rate);
151 _tempo_map->StateChanged.connect (mem_fun (*this, &Session::tempo_map_changed));
154 _non_soloed_outs_muted = false;
155 g_atomic_int_set (&processing_prohibited, 0);
156 _transport_speed = 0;
157 _last_transport_speed = 0;
158 _target_transport_speed = 0;
159 auto_play_legal = false;
160 transport_sub_state = 0;
161 _transport_frame = 0;
162 end_location = new Location (0, 0, _("end"), Location::Flags ((Location::IsMark|Location::IsEnd)));
163 start_location = new Location (0, 0, _("start"), Location::Flags ((Location::IsMark|Location::IsStart)));
164 g_atomic_int_set (&_record_status, Disabled);
165 loop_changing = false;
168 _last_roll_location = 0;
169 _last_record_location = 0;
170 pending_locate_frame = 0;
171 pending_locate_roll = false;
172 pending_locate_flush = false;
173 audio_dstream_buffer_size = 0;
174 midi_dstream_buffer_size = 0;
175 state_was_pending = false;
177 outbound_mtc_smpte_frame = 0;
178 next_quarter_frame_to_send = -1;
179 current_block_size = 0;
180 solo_update_disabled = false;
181 _have_captured = false;
182 _worst_output_latency = 0;
183 _worst_input_latency = 0;
184 _worst_track_latency = 0;
185 _state_of_the_state = StateOfTheState(CannotSave|InitialConnecting|Loading);
188 session_send_mmc = false;
189 session_send_mtc = false;
190 post_transport_work = PostTransportWork (0);
191 g_atomic_int_set (&butler_should_do_transport_work, 0);
192 g_atomic_int_set (&_playback_load, 100);
193 g_atomic_int_set (&_capture_load, 100);
194 g_atomic_int_set (&_playback_load_min, 100);
195 g_atomic_int_set (&_capture_load_min, 100);
198 _exporting_realtime = false;
199 _gain_automation_buffer = 0;
200 _pan_automation_buffer = 0;
202 pending_abort = false;
203 destructive_index = 0;
204 first_file_data_format_reset = true;
205 first_file_header_format_reset = true;
206 butler_thread = (pthread_t) 0;
207 //midi_thread = (pthread_t) 0;
209 AudioDiskstream::allocate_working_buffers();
211 /* default short fade = 15ms */
213 Crossfade::set_short_xfade_length ((nframes_t) floor (config.get_short_xfade_seconds() * frame_rate()));
214 SndFileSource::setup_standard_crossfades (*this, frame_rate());
216 last_mmc_step.tv_sec = 0;
217 last_mmc_step.tv_usec = 0;
220 /* click sounds are unset by default, which causes us to internal
221 waveforms for clicks.
225 click_emphasis_length = 0;
228 process_function = &Session::process_with_events;
230 if (config.get_use_video_sync()) {
231 waiting_for_sync_offset = true;
233 waiting_for_sync_offset = false;
238 _smpte_offset_negative = true;
239 last_smpte_valid = false;
243 last_rr_session_dir = session_dirs.begin();
244 refresh_disk_space ();
246 // set_default_fade (0.2, 5.0); /* steepness, millisecs */
250 average_slave_delta = 1800; // !!! why 1800 ????
251 have_first_delta_accumulator = false;
252 delta_accumulator_cnt = 0;
253 slave_state = Stopped;
255 _engine.GraphReordered.connect (mem_fun (*this, &Session::graph_reordered));
257 /* These are all static "per-class" signals */
259 RegionFactory::CheckNewRegion.connect (mem_fun (*this, &Session::add_region));
260 SourceFactory::SourceCreated.connect (mem_fun (*this, &Session::add_source));
261 PlaylistFactory::PlaylistCreated.connect (mem_fun (*this, &Session::add_playlist));
262 Processor::ProcessorCreated.connect (mem_fun (*this, &Session::add_processor));
263 NamedSelection::NamedSelectionCreated.connect (mem_fun (*this, &Session::add_named_selection));
264 AutomationList::AutomationListCreated.connect (mem_fun (*this, &Session::add_automation_list));
266 Controllable::Destroyed.connect (mem_fun (*this, &Session::remove_controllable));
268 IO::PortCountChanged.connect (mem_fun (*this, &Session::ensure_buffers));
270 /* stop IO objects from doing stuff until we're ready for them */
272 Delivery::disable_panners ();
273 IO::disable_connecting ();
277 Session::second_stage_init (bool new_session)
279 AudioFileSource::set_peak_dir (_session_dir->peak_path().to_string());
282 if (load_state (_current_snapshot_name)) {
285 remove_empty_sounds ();
288 if (start_butler_thread()) {
292 if (start_midi_thread ()) {
296 // set_state() will call setup_raid_path(), but if it's a new session we need
297 // to call setup_raid_path() here.
300 if (set_state (*state_tree->root())) {
304 setup_raid_path(_path);
307 /* we can't save till after ::when_engine_running() is called,
308 because otherwise we save state with no connections made.
309 therefore, we reset _state_of_the_state because ::set_state()
310 will have cleared it.
312 we also have to include Loading so that any events that get
313 generated between here and the end of ::when_engine_running()
314 will be processed directly rather than queued.
317 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave|Loading);
320 _locations.changed.connect (mem_fun (this, &Session::locations_changed));
321 _locations.added.connect (mem_fun (this, &Session::locations_added));
322 setup_click_sounds (0);
323 setup_midi_control ();
325 /* Pay attention ... */
327 _engine.Halted.connect (mem_fun (*this, &Session::engine_halted));
328 _engine.Xrun.connect (mem_fun (*this, &Session::xrun_recovery));
331 when_engine_running();
334 /* handle this one in a different way than all others, so that its clear what happened */
336 catch (AudioEngine::PortRegistrationFailure& err) {
337 error << err.what() << endmsg;
345 BootMessage (_("Reset Remote Controls"));
347 send_full_time_code (0);
348 _engine.transport_locate (0);
349 deliver_mmc (MIDI::MachineControl::cmdMmcReset, 0);
350 deliver_mmc (MIDI::MachineControl::cmdLocate, 0);
352 MidiClockTicker::instance().set_session(*this);
353 MIDI::Name::MidiPatchManager::instance().set_session(*this);
355 /* initial program change will be delivered later; see ::config_changed() */
357 BootMessage (_("Reset Control Protocols"));
359 ControlProtocolManager::instance().set_session (*this);
361 config.set_end_marker_is_free (new_session);
363 _state_of_the_state = Clean;
365 DirtyChanged (); /* EMIT SIGNAL */
367 if (state_was_pending) {
368 save_state (_current_snapshot_name);
369 remove_pending_capture_state ();
370 state_was_pending = false;
373 BootMessage (_("Session loading complete"));
379 Session::raid_path () const
381 SearchPath raid_search_path;
383 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
384 raid_search_path += sys::path((*i).path);
387 return raid_search_path.to_string ();
391 Session::setup_raid_path (string path)
400 session_dirs.clear ();
402 SearchPath search_path(path);
403 SearchPath sound_search_path;
404 SearchPath midi_search_path;
406 for (SearchPath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
407 sp.path = (*i).to_string ();
408 sp.blocks = 0; // not needed
409 session_dirs.push_back (sp);
411 SessionDirectory sdir(sp.path);
413 sound_search_path += sdir.sound_path ();
414 midi_search_path += sdir.midi_path ();
417 // set the search path for each data type
418 FileSource::set_search_path (DataType::AUDIO, sound_search_path.to_string ());
419 SMFSource::set_search_path (DataType::MIDI, midi_search_path.to_string ());
421 // reset the round-robin soundfile path thingie
422 last_rr_session_dir = session_dirs.begin();
426 Session::ensure_subdirs ()
430 dir = session_directory().peak_path().to_string();
432 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
433 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
437 dir = session_directory().sound_path().to_string();
439 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
440 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
444 dir = session_directory().midi_path().to_string();
446 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
447 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
451 dir = session_directory().dead_sound_path().to_string();
453 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
454 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
458 dir = session_directory().export_path().to_string();
460 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
461 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
465 dir = analysis_dir ();
467 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
468 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
476 Session::create (bool& new_session, const string& mix_template, nframes_t initial_length)
479 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
480 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
484 if (ensure_subdirs ()) {
488 /* check new_session so we don't overwrite an existing one */
490 if (!mix_template.empty()) {
491 std::string in_path = mix_template;
493 ifstream in(in_path.c_str());
496 string out_path = _path;
498 out_path += statefile_suffix;
500 ofstream out(out_path.c_str());
505 // okay, session is set up. Treat like normal saved
506 // session from now on.
512 error << string_compose (_("Could not open %1 for writing mix template"), out_path)
518 error << string_compose (_("Could not open mix template %1 for reading"), in_path)
525 /* Instantiate metadata */
527 _metadata = new SessionMetadata ();
529 /* set initial start + end point */
531 start_location->set_end (0);
532 _locations.add (start_location);
534 end_location->set_end (initial_length);
535 _locations.add (end_location);
537 _state_of_the_state = Clean;
546 Session::load_diskstreams (const XMLNode& node)
549 XMLNodeConstIterator citer;
551 clist = node.children();
553 for (citer = clist.begin(); citer != clist.end(); ++citer) {
556 /* diskstreams added automatically by DiskstreamCreated handler */
557 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
558 boost::shared_ptr<AudioDiskstream> dstream (new AudioDiskstream (*this, **citer));
559 add_diskstream (dstream);
560 } else if ((*citer)->name() == "MidiDiskstream") {
561 boost::shared_ptr<MidiDiskstream> dstream (new MidiDiskstream (*this, **citer));
562 add_diskstream (dstream);
564 error << _("Session: unknown diskstream type in XML") << endmsg;
568 catch (failed_constructor& err) {
569 error << _("Session: could not load diskstream via XML state") << endmsg;
578 Session::maybe_write_autosave()
580 if (dirty() && record_status() != Recording) {
581 save_state("", true);
586 Session::remove_pending_capture_state ()
588 sys::path pending_state_file_path(_session_dir->root_path());
590 pending_state_file_path /= _current_snapshot_name + pending_suffix;
594 sys::remove (pending_state_file_path);
596 catch(sys::filesystem_error& ex)
598 error << string_compose(_("Could remove pending capture state at path \"%1\" (%2)"),
599 pending_state_file_path.to_string(), ex.what()) << endmsg;
603 /** Rename a state file.
604 * @param snapshot_name Snapshot name.
607 Session::rename_state (string old_name, string new_name)
609 if (old_name == _current_snapshot_name || old_name == _name) {
610 /* refuse to rename the current snapshot or the "main" one */
614 const string old_xml_filename = old_name + statefile_suffix;
615 const string new_xml_filename = new_name + statefile_suffix;
617 const sys::path old_xml_path = _session_dir->root_path() / old_xml_filename;
618 const sys::path new_xml_path = _session_dir->root_path() / new_xml_filename;
622 sys::rename (old_xml_path, new_xml_path);
624 catch (const sys::filesystem_error& err)
626 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
627 old_name, new_name, err.what()) << endmsg;
631 /** Remove a state file.
632 * @param snapshot_name Snapshot name.
635 Session::remove_state (string snapshot_name)
637 if (snapshot_name == _current_snapshot_name || snapshot_name == _name) {
638 // refuse to remove the current snapshot or the "main" one
642 sys::path xml_path(_session_dir->root_path());
644 xml_path /= snapshot_name + statefile_suffix;
646 if (!create_backup_file (xml_path)) {
647 // don't remove it if a backup can't be made
648 // create_backup_file will log the error.
653 sys::remove (xml_path);
657 Session::save_state (string snapshot_name, bool pending)
660 sys::path xml_path(_session_dir->root_path());
662 if (_state_of_the_state & CannotSave) {
666 if (!_engine.connected ()) {
667 error << _("Ardour's audio engine is not connected and state saving would lose all I/O connections. Session not saved")
672 /* tell sources we're saving first, in case they write out to a new file
673 * which should be saved with the state rather than the old one */
674 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i)
675 i->second->session_saved();
677 tree.set_root (&get_state());
679 if (snapshot_name.empty()) {
680 snapshot_name = _current_snapshot_name;
685 /* proper save: use statefile_suffix (.ardour in English) */
687 xml_path /= snapshot_name + statefile_suffix;
689 /* make a backup copy of the old file */
691 if (sys::exists(xml_path) && !create_backup_file (xml_path)) {
692 // create_backup_file will log the error
698 /* pending save: use pending_suffix (.pending in English) */
699 xml_path /= snapshot_name + pending_suffix;
702 sys::path tmp_path(_session_dir->root_path());
704 tmp_path /= snapshot_name + temp_suffix;
706 // cerr << "actually writing state to " << xml_path.to_string() << endl;
708 if (!tree.write (tmp_path.to_string())) {
709 error << string_compose (_("state could not be saved to %1"), tmp_path.to_string()) << endmsg;
710 sys::remove (tmp_path);
715 if (rename (tmp_path.to_string().c_str(), xml_path.to_string().c_str()) != 0) {
716 error << string_compose (_("could not rename temporary session file %1 to %2"),
717 tmp_path.to_string(), xml_path.to_string()) << endmsg;
718 sys::remove (tmp_path);
725 save_history (snapshot_name);
727 bool was_dirty = dirty();
729 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
732 DirtyChanged (); /* EMIT SIGNAL */
735 StateSaved (snapshot_name); /* EMIT SIGNAL */
742 Session::restore_state (string snapshot_name)
744 if (load_state (snapshot_name) == 0) {
745 set_state (*state_tree->root());
752 Session::load_state (string snapshot_name)
757 state_was_pending = false;
759 /* check for leftover pending state from a crashed capture attempt */
761 sys::path xmlpath(_session_dir->root_path());
762 xmlpath /= snapshot_name + pending_suffix;
764 if (sys::exists (xmlpath)) {
766 /* there is pending state from a crashed capture attempt */
768 if (AskAboutPendingState()) {
769 state_was_pending = true;
773 if (!state_was_pending) {
774 xmlpath = _session_dir->root_path();
775 xmlpath /= snapshot_name + statefile_suffix;
778 if (!sys::exists (xmlpath)) {
779 error << string_compose(_("%1: session state information file \"%2\" doesn't exist!"), _name, xmlpath.to_string()) << endmsg;
783 state_tree = new XMLTree;
787 if (!state_tree->read (xmlpath.to_string())) {
788 error << string_compose(_("Could not understand ardour file %1"), xmlpath.to_string()) << endmsg;
794 XMLNode& root (*state_tree->root());
796 if (root.name() != X_("Session")) {
797 error << string_compose (_("Session file %1 is not an Ardour session"), xmlpath.to_string()) << endmsg;
803 const XMLProperty* prop;
804 bool is_old = false; // session is _very_ old (pre-2.0)
806 if ((prop = root.property ("version")) == 0) {
807 /* no version implies very old version of Ardour */
811 major_version = atoi (prop->value().c_str()); // grab just the first number before the period
812 if (major_version < 2) {
819 sys::path backup_path(_session_dir->root_path());
821 backup_path /= snapshot_name + "-1" + statefile_suffix;
823 // only create a backup once
824 if (sys::exists (backup_path)) {
828 info << string_compose (_("Copying old session file %1 to %2\nUse %2 with Ardour versions before 2.0 from now on"),
829 xmlpath.to_string(), backup_path.to_string())
834 sys::copy_file (xmlpath, backup_path);
836 catch(sys::filesystem_error& ex)
838 error << string_compose (_("Unable to make backup of state file %1 (%2)"),
839 xmlpath.to_string(), ex.what())
849 Session::load_options (const XMLNode& node)
851 LocaleGuard lg (X_("POSIX"));
853 config.set_variables (node);
855 /* now reset MIDI ports because the session can have its own
871 Session::get_template()
873 /* if we don't disable rec-enable, diskstreams
874 will believe they need to store their capture
875 sources in their state node.
878 disable_record (false);
884 Session::state(bool full_state)
886 XMLNode* node = new XMLNode("Session");
889 // store libardour version, just in case
891 snprintf(buf, sizeof(buf), "%d.%d.%d", libardour3_major_version, libardour3_minor_version, libardour3_micro_version);
892 node->add_property("version", string(buf));
894 /* store configuration settings */
898 node->add_property ("name", _name);
899 snprintf (buf, sizeof (buf), "%" PRId32, _nominal_frame_rate);
900 node->add_property ("sample-rate", buf);
902 if (session_dirs.size() > 1) {
906 vector<space_and_path>::iterator i = session_dirs.begin();
907 vector<space_and_path>::iterator next;
909 ++i; /* skip the first one */
913 while (i != session_dirs.end()) {
917 if (next != session_dirs.end()) {
927 child = node->add_child ("Path");
928 child->add_content (p);
932 /* save the ID counter */
934 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
935 node->add_property ("id-counter", buf);
937 /* various options */
939 node->add_child_nocopy (config.get_variables ());
941 node->add_child_nocopy (_metadata->get_state());
943 child = node->add_child ("Sources");
946 Glib::Mutex::Lock sl (source_lock);
948 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
950 /* Don't save information about non-destructive file sources that are empty */
951 /* FIXME: MIDI breaks if this is made FileSource like it should be... */
953 boost::shared_ptr<AudioFileSource> fs;
954 if ((fs = boost::dynamic_pointer_cast<AudioFileSource> (siter->second)) != 0) {
955 if (!fs->destructive()) {
956 if (fs->length(fs->timeline_position()) == 0) {
962 child->add_child_nocopy (siter->second->get_state());
966 child = node->add_child ("Regions");
969 Glib::Mutex::Lock rl (region_lock);
971 for (RegionList::const_iterator i = regions.begin(); i != regions.end(); ++i) {
973 /* only store regions not attached to playlists */
975 if (i->second->playlist() == 0) {
976 child->add_child_nocopy (i->second->state (true));
981 child = node->add_child ("DiskStreams");
984 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
985 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
986 if (!(*i)->hidden()) {
987 child->add_child_nocopy ((*i)->get_state());
993 node->add_child_nocopy (_locations.get_state());
995 // for a template, just create a new Locations, populate it
996 // with the default start and end, and get the state for that.
998 Location* start = new Location(0, 0, _("start"), Location::Flags ((Location::IsMark|Location::IsStart)));
999 Location* end = new Location(0, 0, _("end"), Location::Flags ((Location::IsMark|Location::IsEnd)));
1002 end->set_end(compute_initial_length());
1004 node->add_child_nocopy (loc.get_state());
1007 child = node->add_child ("Bundles");
1009 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1010 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1011 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1013 child->add_child_nocopy (b->get_state());
1018 child = node->add_child ("Routes");
1020 boost::shared_ptr<RouteList> r = routes.reader ();
1022 RoutePublicOrderSorter cmp;
1023 RouteList public_order (*r);
1024 public_order.sort (cmp);
1026 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1027 if (!(*i)->is_hidden()) {
1029 child->add_child_nocopy ((*i)->get_state());
1031 child->add_child_nocopy ((*i)->get_template());
1038 child = node->add_child ("RouteGroups");
1039 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1040 child->add_child_nocopy ((*i)->get_state());
1043 child = node->add_child ("Playlists");
1044 for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
1045 if (!(*i)->hidden()) {
1046 if (!(*i)->empty()) {
1048 child->add_child_nocopy ((*i)->get_state());
1050 child->add_child_nocopy ((*i)->get_template());
1056 child = node->add_child ("UnusedPlaylists");
1057 for (PlaylistList::iterator i = unused_playlists.begin(); i != unused_playlists.end(); ++i) {
1058 if (!(*i)->hidden()) {
1059 if (!(*i)->empty()) {
1061 child->add_child_nocopy ((*i)->get_state());
1063 child->add_child_nocopy ((*i)->get_template());
1071 child = node->add_child ("Click");
1072 child->add_child_nocopy (_click_io->state (full_state));
1076 child = node->add_child ("NamedSelections");
1077 for (NamedSelectionList::iterator i = named_selections.begin(); i != named_selections.end(); ++i) {
1079 child->add_child_nocopy ((*i)->get_state());
1084 node->add_child_nocopy (_tempo_map->get_state());
1086 node->add_child_nocopy (get_control_protocol_state());
1089 node->add_child_copy (*_extra_xml);
1096 Session::get_control_protocol_state ()
1098 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1099 return cpm.get_state();
1103 Session::set_state (const XMLNode& node)
1107 const XMLProperty* prop;
1110 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1112 if (node.name() != X_("Session")){
1113 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1117 if ((prop = node.property ("name")) != 0) {
1118 _name = prop->value ();
1121 if ((prop = node.property (X_("sample-rate"))) != 0) {
1123 _nominal_frame_rate = atoi (prop->value());
1125 if (_nominal_frame_rate != _current_frame_rate) {
1126 if (AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate)) {
1132 setup_raid_path(_session_dir->root_path().to_string());
1134 if ((prop = node.property (X_("id-counter"))) != 0) {
1136 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1137 ID::init_counter (x);
1139 /* old sessions used a timebased counter, so fake
1140 the startup ID counter based on a standard
1145 ID::init_counter (now);
1149 IO::disable_connecting ();
1151 /* Object loading order:
1156 MIDI Control // relies on data from Options/Config
1170 if ((child = find_named_node (node, "Extra")) != 0) {
1171 _extra_xml = new XMLNode (*child);
1174 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1175 load_options (*child);
1176 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1177 load_options (*child);
1179 error << _("Session: XML state has no options section") << endmsg;
1182 if (use_config_midi_ports ()) {
1185 if ((child = find_named_node (node, "Metadata")) == 0) {
1186 warning << _("Session: XML state has no metadata section (2.0 session?)") << endmsg;
1187 } else if (_metadata->set_state (*child)) {
1191 if ((child = find_named_node (node, "Locations")) == 0) {
1192 error << _("Session: XML state has no locations section") << endmsg;
1194 } else if (_locations.set_state (*child)) {
1200 if ((location = _locations.auto_loop_location()) != 0) {
1201 set_auto_loop_location (location);
1204 if ((location = _locations.auto_punch_location()) != 0) {
1205 set_auto_punch_location (location);
1208 if ((location = _locations.end_location()) == 0) {
1209 _locations.add (end_location);
1211 delete end_location;
1212 end_location = location;
1215 if ((location = _locations.start_location()) == 0) {
1216 _locations.add (start_location);
1218 delete start_location;
1219 start_location = location;
1222 AudioFileSource::set_header_position_offset (start_location->start());
1224 if ((child = find_named_node (node, "Sources")) == 0) {
1225 error << _("Session: XML state has no sources section") << endmsg;
1227 } else if (load_sources (*child)) {
1231 if ((child = find_named_node (node, "Regions")) == 0) {
1232 error << _("Session: XML state has no Regions section") << endmsg;
1234 } else if (load_regions (*child)) {
1238 if ((child = find_named_node (node, "Playlists")) == 0) {
1239 error << _("Session: XML state has no playlists section") << endmsg;
1241 } else if (load_playlists (*child)) {
1245 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1247 } else if (load_unused_playlists (*child)) {
1251 if ((child = find_named_node (node, "NamedSelections")) != 0) {
1252 if (load_named_selections (*child)) {
1257 if ((child = find_named_node (node, "DiskStreams")) == 0) {
1258 error << _("Session: XML state has no diskstreams section") << endmsg;
1260 } else if (load_diskstreams (*child)) {
1264 if ((child = find_named_node (node, "Bundles")) == 0) {
1265 warning << _("Session: XML state has no bundles section (2.0 session?)") << endmsg;
1268 /* We can't load Bundles yet as they need to be able
1269 to convert from port names to Port objects, which can't happen until
1271 _bundle_xml_node = new XMLNode (*child);
1274 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1275 error << _("Session: XML state has no route groups section") << endmsg;
1277 } else if (load_route_groups (*child)) {
1281 if ((child = find_named_node (node, "TempoMap")) == 0) {
1282 error << _("Session: XML state has no Tempo Map section") << endmsg;
1284 } else if (_tempo_map->set_state (*child)) {
1288 if ((child = find_named_node (node, "Routes")) == 0) {
1289 error << _("Session: XML state has no routes section") << endmsg;
1291 } else if (load_routes (*child)) {
1295 if ((child = find_named_node (node, "Click")) == 0) {
1296 warning << _("Session: XML state has no click section") << endmsg;
1297 } else if (_click_io) {
1298 _click_io->set_state (*child);
1301 if ((child = find_named_node (node, "ControlProtocols")) != 0) {
1302 ControlProtocolManager::instance().set_protocol_states (*child);
1305 /* here beginneth the second phase ... */
1307 StateReady (); /* EMIT SIGNAL */
1316 Session::load_routes (const XMLNode& node)
1319 XMLNodeConstIterator niter;
1320 RouteList new_routes;
1322 nlist = node.children();
1326 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1328 boost::shared_ptr<Route> route (XMLRouteFactory (**niter));
1331 error << _("Session: cannot create Route from XML description.") << endmsg;
1335 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1337 new_routes.push_back (route);
1340 add_routes (new_routes, false);
1345 boost::shared_ptr<Route>
1346 Session::XMLRouteFactory (const XMLNode& node)
1348 if (node.name() != "Route") {
1349 return boost::shared_ptr<Route> ((Route*) 0);
1352 bool has_diskstream = (node.property ("diskstream") != 0 || node.property ("diskstream-id") != 0);
1354 DataType type = DataType::AUDIO;
1355 const XMLProperty* prop = node.property("default-type");
1358 type = DataType(prop->value());
1361 assert(type != DataType::NIL);
1363 if (has_diskstream) {
1364 if (type == DataType::AUDIO) {
1365 boost::shared_ptr<Route> ret (new AudioTrack (*this, node));
1368 boost::shared_ptr<Route> ret (new MidiTrack (*this, node));
1372 boost::shared_ptr<Route> ret (new Route (*this, node));
1378 Session::load_regions (const XMLNode& node)
1381 XMLNodeConstIterator niter;
1382 boost::shared_ptr<Region> region;
1384 nlist = node.children();
1388 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1389 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1390 error << _("Session: cannot create Region from XML description.");
1391 const XMLProperty *name = (**niter).property("name");
1394 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1404 boost::shared_ptr<Region>
1405 Session::XMLRegionFactory (const XMLNode& node, bool full)
1407 const XMLProperty* type = node.property("type");
1411 if ( !type || type->value() == "audio" ) {
1413 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1415 } else if (type->value() == "midi") {
1417 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1421 } catch (failed_constructor& err) {
1422 return boost::shared_ptr<Region> ();
1425 return boost::shared_ptr<Region> ();
1428 boost::shared_ptr<AudioRegion>
1429 Session::XMLAudioRegionFactory (const XMLNode& node, bool full)
1431 const XMLProperty* prop;
1432 boost::shared_ptr<Source> source;
1433 boost::shared_ptr<AudioSource> as;
1435 SourceList master_sources;
1436 uint32_t nchans = 1;
1439 if (node.name() != X_("Region")) {
1440 return boost::shared_ptr<AudioRegion>();
1443 if ((prop = node.property (X_("channels"))) != 0) {
1444 nchans = atoi (prop->value().c_str());
1447 if ((prop = node.property ("name")) == 0) {
1448 cerr << "no name for this region\n";
1452 if ((prop = node.property (X_("source-0"))) == 0) {
1453 if ((prop = node.property ("source")) == 0) {
1454 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1455 return boost::shared_ptr<AudioRegion>();
1459 PBD::ID s_id (prop->value());
1461 if ((source = source_by_id (s_id)) == 0) {
1462 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1463 return boost::shared_ptr<AudioRegion>();
1466 as = boost::dynamic_pointer_cast<AudioSource>(source);
1468 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1469 return boost::shared_ptr<AudioRegion>();
1472 sources.push_back (as);
1474 /* pickup other channels */
1476 for (uint32_t n=1; n < nchans; ++n) {
1477 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1478 if ((prop = node.property (buf)) != 0) {
1480 PBD::ID id2 (prop->value());
1482 if ((source = source_by_id (id2)) == 0) {
1483 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1484 return boost::shared_ptr<AudioRegion>();
1487 as = boost::dynamic_pointer_cast<AudioSource>(source);
1489 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1490 return boost::shared_ptr<AudioRegion>();
1492 sources.push_back (as);
1496 for (uint32_t n = 0; n < nchans; ++n) {
1497 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1498 if ((prop = node.property (buf)) != 0) {
1500 PBD::ID id2 (prop->value());
1502 if ((source = source_by_id (id2)) == 0) {
1503 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1504 return boost::shared_ptr<AudioRegion>();
1507 as = boost::dynamic_pointer_cast<AudioSource>(source);
1509 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1510 return boost::shared_ptr<AudioRegion>();
1512 master_sources.push_back (as);
1517 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1519 /* a final detail: this is the one and only place that we know how long missing files are */
1521 if (region->whole_file()) {
1522 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1523 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1525 sfp->set_length (region->length());
1530 if (!master_sources.empty()) {
1531 if (master_sources.size() != nchans) {
1532 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1534 region->set_master_sources (master_sources);
1542 catch (failed_constructor& err) {
1543 return boost::shared_ptr<AudioRegion>();
1547 boost::shared_ptr<MidiRegion>
1548 Session::XMLMidiRegionFactory (const XMLNode& node, bool full)
1550 const XMLProperty* prop;
1551 boost::shared_ptr<Source> source;
1552 boost::shared_ptr<MidiSource> ms;
1554 uint32_t nchans = 1;
1556 if (node.name() != X_("Region")) {
1557 return boost::shared_ptr<MidiRegion>();
1560 if ((prop = node.property (X_("channels"))) != 0) {
1561 nchans = atoi (prop->value().c_str());
1564 if ((prop = node.property ("name")) == 0) {
1565 cerr << "no name for this region\n";
1569 // Multiple midi channels? that's just crazy talk
1570 assert(nchans == 1);
1572 if ((prop = node.property (X_("source-0"))) == 0) {
1573 if ((prop = node.property ("source")) == 0) {
1574 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1575 return boost::shared_ptr<MidiRegion>();
1579 PBD::ID s_id (prop->value());
1581 if ((source = source_by_id (s_id)) == 0) {
1582 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1583 return boost::shared_ptr<MidiRegion>();
1586 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1588 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1589 return boost::shared_ptr<MidiRegion>();
1592 sources.push_back (ms);
1595 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1596 /* a final detail: this is the one and only place that we know how long missing files are */
1598 if (region->whole_file()) {
1599 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1600 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1602 sfp->set_length (region->length());
1610 catch (failed_constructor& err) {
1611 return boost::shared_ptr<MidiRegion>();
1616 Session::get_sources_as_xml ()
1619 XMLNode* node = new XMLNode (X_("Sources"));
1620 Glib::Mutex::Lock lm (source_lock);
1622 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1623 node->add_child_nocopy (i->second->get_state());
1630 Session::path_from_region_name (DataType type, string name, string identifier)
1632 char buf[PATH_MAX+1];
1634 SessionDirectory sdir(get_best_session_directory_for_new_source());
1635 sys::path source_dir = ((type == DataType::AUDIO)
1636 ? sdir.sound_path() : sdir.midi_path());
1638 string ext = ((type == DataType::AUDIO) ? ".wav" : ".mid");
1640 for (n = 0; n < 999999; ++n) {
1641 if (identifier.length()) {
1642 snprintf (buf, sizeof(buf), "%s%s%" PRIu32 "%s", name.c_str(),
1643 identifier.c_str(), n, ext.c_str());
1645 snprintf (buf, sizeof(buf), "%s-%" PRIu32 "%s", name.c_str(),
1649 sys::path source_path = source_dir / buf;
1651 if (!sys::exists (source_path)) {
1652 return source_path.to_string();
1656 error << string_compose (_("cannot create new file from region name \"%1\" with ident = \"%2\": too many existing files with similar names"),
1665 Session::load_sources (const XMLNode& node)
1668 XMLNodeConstIterator niter;
1669 boost::shared_ptr<Source> source;
1671 nlist = node.children();
1675 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1677 if ((source = XMLSourceFactory (**niter)) == 0) {
1678 error << _("Session: cannot create Source from XML description.") << endmsg;
1680 } catch (MissingSource& err) {
1681 warning << _("A sound file is missing. It will be replaced by silence.") << endmsg;
1682 source = SourceFactory::createSilent (*this, **niter, max_frames, _current_frame_rate);
1689 boost::shared_ptr<Source>
1690 Session::XMLSourceFactory (const XMLNode& node)
1692 if (node.name() != "Source") {
1693 return boost::shared_ptr<Source>();
1697 /* note: do peak building in another thread when loading session state */
1698 return SourceFactory::create (*this, node, true);
1701 catch (failed_constructor& err) {
1702 error << _("Found a sound file that cannot be used by Ardour. Talk to the progammers.") << endmsg;
1703 return boost::shared_ptr<Source>();
1708 Session::save_template (string template_name)
1712 if (_state_of_the_state & CannotSave) {
1716 sys::path user_template_dir(user_template_directory());
1720 sys::create_directories (user_template_dir);
1722 catch(sys::filesystem_error& ex)
1724 error << string_compose(_("Could not create mix templates directory \"%1\" (%2)"),
1725 user_template_dir.to_string(), ex.what()) << endmsg;
1729 tree.set_root (&get_template());
1731 sys::path template_file_path(user_template_dir);
1732 template_file_path /= template_name + template_suffix;
1734 if (sys::exists (template_file_path))
1736 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
1737 template_file_path.to_string()) << endmsg;
1741 if (!tree.write (template_file_path.to_string())) {
1742 error << _("mix template not saved") << endmsg;
1750 Session::rename_template (string old_name, string new_name)
1752 sys::path old_path (user_template_directory());
1753 old_path /= old_name + template_suffix;
1755 sys::path new_path(user_template_directory());
1756 new_path /= new_name + template_suffix;
1758 if (sys::exists (new_path)) {
1759 warning << string_compose(_("Template \"%1\" already exists - template not renamed"),
1760 new_path.to_string()) << endmsg;
1765 sys::rename (old_path, new_path);
1773 Session::delete_template (string name)
1775 sys::path path = user_template_directory();
1776 path /= name + template_suffix;
1787 Session::refresh_disk_space ()
1790 struct statfs statfsbuf;
1791 vector<space_and_path>::iterator i;
1792 Glib::Mutex::Lock lm (space_lock);
1795 /* get freespace on every FS that is part of the session path */
1797 _total_free_4k_blocks = 0;
1799 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
1800 statfs ((*i).path.c_str(), &statfsbuf);
1802 scale = statfsbuf.f_bsize/4096.0;
1804 (*i).blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
1805 _total_free_4k_blocks += (*i).blocks;
1811 Session::get_best_session_directory_for_new_source ()
1813 vector<space_and_path>::iterator i;
1814 string result = _session_dir->root_path().to_string();
1816 /* handle common case without system calls */
1818 if (session_dirs.size() == 1) {
1822 /* OK, here's the algorithm we're following here:
1824 We want to select which directory to use for
1825 the next file source to be created. Ideally,
1826 we'd like to use a round-robin process so as to
1827 get maximum performance benefits from splitting
1828 the files across multiple disks.
1830 However, in situations without much diskspace, an
1831 RR approach may end up filling up a filesystem
1832 with new files while others still have space.
1833 Its therefore important to pay some attention to
1834 the freespace in the filesystem holding each
1835 directory as well. However, if we did that by
1836 itself, we'd keep creating new files in the file
1837 system with the most space until it was as full
1838 as all others, thus negating any performance
1839 benefits of this RAID-1 like approach.
1841 So, we use a user-configurable space threshold. If
1842 there are at least 2 filesystems with more than this
1843 much space available, we use RR selection between them.
1844 If not, then we pick the filesystem with the most space.
1846 This gets a good balance between the two
1850 refresh_disk_space ();
1852 int free_enough = 0;
1854 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
1855 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
1860 if (free_enough >= 2) {
1861 /* use RR selection process, ensuring that the one
1865 i = last_rr_session_dir;
1868 if (++i == session_dirs.end()) {
1869 i = session_dirs.begin();
1872 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
1873 if (create_session_directory ((*i).path)) {
1875 last_rr_session_dir = i;
1880 } while (i != last_rr_session_dir);
1884 /* pick FS with the most freespace (and that
1885 seems to actually work ...)
1888 vector<space_and_path> sorted;
1889 space_and_path_ascending_cmp cmp;
1891 sorted = session_dirs;
1892 sort (sorted.begin(), sorted.end(), cmp);
1894 for (i = sorted.begin(); i != sorted.end(); ++i) {
1895 if (create_session_directory ((*i).path)) {
1897 last_rr_session_dir = i;
1907 Session::load_playlists (const XMLNode& node)
1910 XMLNodeConstIterator niter;
1911 boost::shared_ptr<Playlist> playlist;
1913 nlist = node.children();
1917 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1919 if ((playlist = XMLPlaylistFactory (**niter)) == 0) {
1920 error << _("Session: cannot create Playlist from XML description.") << endmsg;
1928 Session::load_unused_playlists (const XMLNode& node)
1931 XMLNodeConstIterator niter;
1932 boost::shared_ptr<Playlist> playlist;
1934 nlist = node.children();
1938 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1940 if ((playlist = XMLPlaylistFactory (**niter)) == 0) {
1941 error << _("Session: cannot create Playlist from XML description.") << endmsg;
1945 // now manually untrack it
1947 track_playlist (false, boost::weak_ptr<Playlist> (playlist));
1953 boost::shared_ptr<Playlist>
1954 Session::XMLPlaylistFactory (const XMLNode& node)
1957 return PlaylistFactory::create (*this, node);
1960 catch (failed_constructor& err) {
1961 return boost::shared_ptr<Playlist>();
1966 Session::load_named_selections (const XMLNode& node)
1969 XMLNodeConstIterator niter;
1972 nlist = node.children();
1976 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1978 if ((ns = XMLNamedSelectionFactory (**niter)) == 0) {
1979 error << _("Session: cannot create Named Selection from XML description.") << endmsg;
1987 Session::XMLNamedSelectionFactory (const XMLNode& node)
1990 return new NamedSelection (*this, node);
1993 catch (failed_constructor& err) {
1999 Session::automation_dir () const
2001 return Glib::build_filename (_path, "automation");
2005 Session::analysis_dir () const
2007 return Glib::build_filename (_path, "analysis");
2011 Session::load_bundles (XMLNode const & node)
2013 XMLNodeList nlist = node.children();
2014 XMLNodeConstIterator niter;
2018 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2019 if ((*niter)->name() == "InputBundle") {
2020 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2021 } else if ((*niter)->name() == "OutputBundle") {
2022 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2024 error << string_compose(_("Unknown node \"%1\" found in Bundles list from state file"), (*niter)->name()) << endmsg;
2033 Session::load_route_groups (const XMLNode& node)
2035 XMLNodeList nlist = node.children();
2036 XMLNodeConstIterator niter;
2040 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2041 if ((*niter)->name() == "RouteGroup") {
2042 RouteGroup* rg = new RouteGroup (*this, "");
2043 add_route_group (rg);
2044 rg->set_state (**niter);
2052 Session::auto_save()
2054 save_state (_current_snapshot_name);
2058 state_file_filter (const string &str, void *arg)
2060 return (str.length() > strlen(statefile_suffix) &&
2061 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2065 bool operator()(const string* a, const string* b) {
2071 remove_end(string* state)
2073 string statename(*state);
2075 string::size_type start,end;
2076 if ((start = statename.find_last_of ('/')) != string::npos) {
2077 statename = statename.substr (start+1);
2080 if ((end = statename.rfind(".ardour")) == string::npos) {
2081 end = statename.length();
2084 return new string(statename.substr (0, end));
2088 Session::possible_states (string path)
2090 PathScanner scanner;
2091 vector<string*>* states = scanner (path, state_file_filter, 0, false, false);
2093 transform(states->begin(), states->end(), states->begin(), remove_end);
2096 sort (states->begin(), states->end(), cmp);
2102 Session::possible_states () const
2104 return possible_states(_path);
2108 Session::add_route_group (RouteGroup* g)
2110 _route_groups.push_back (g);
2111 route_group_added (g); /* EMIT SIGNAL */
2116 Session::remove_route_group (RouteGroup& rg)
2118 list<RouteGroup*>::iterator i;
2120 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2121 (*i)->apply (&Route::drop_route_group, this);
2122 _route_groups.erase (i);
2123 route_group_removed (); /* EMIT SIGNAL */
2131 Session::route_group_by_name (string name)
2133 list<RouteGroup *>::iterator i;
2135 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2136 if ((*i)->name() == name) {
2144 Session::begin_reversible_command(const string& name)
2146 UndoTransaction* trans = new UndoTransaction();
2147 trans->set_name(name);
2148 if (!_current_trans.empty()) {
2149 _current_trans.top()->add_command(trans);
2151 _current_trans.push(trans);
2155 Session::commit_reversible_command(Command *cmd)
2157 assert(!_current_trans.empty());
2161 _current_trans.top()->add_command(cmd);
2164 if (_current_trans.top()->empty()) {
2165 _current_trans.pop();
2169 gettimeofday(&now, 0);
2170 _current_trans.top()->set_timestamp(now);
2172 _history.add(_current_trans.top());
2173 _current_trans.pop();
2176 Session::GlobalRouteBooleanState
2177 Session::get_global_route_boolean (bool (Route::*method)(void) const)
2179 GlobalRouteBooleanState s;
2180 boost::shared_ptr<RouteList> r = routes.reader ();
2182 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
2183 if (!(*i)->is_hidden()) {
2184 RouteBooleanState v;
2187 Route* r = (*i).get();
2188 v.second = (r->*method)();
2197 Session::GlobalRouteMeterState
2198 Session::get_global_route_metering ()
2200 GlobalRouteMeterState s;
2201 boost::shared_ptr<RouteList> r = routes.reader ();
2203 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
2204 if (!(*i)->is_hidden()) {
2208 v.second = (*i)->meter_point();
2218 Session::set_global_route_metering (GlobalRouteMeterState s, void* arg)
2220 for (GlobalRouteMeterState::iterator i = s.begin(); i != s.end(); ++i) {
2222 boost::shared_ptr<Route> r = (i->first.lock());
2225 r->set_meter_point (i->second, arg);
2231 Session::set_global_route_boolean (GlobalRouteBooleanState s, void (Route::*method)(bool, void*), void* arg)
2233 for (GlobalRouteBooleanState::iterator i = s.begin(); i != s.end(); ++i) {
2235 boost::shared_ptr<Route> r = (i->first.lock());
2238 Route* rp = r.get();
2239 (rp->*method) (i->second, arg);
2245 Session::set_global_mute (GlobalRouteBooleanState s, void* src)
2247 set_global_route_boolean (s, &Route::set_mute, src);
2251 Session::set_global_solo (GlobalRouteBooleanState s, void* src)
2253 set_global_route_boolean (s, &Route::set_solo, src);
2257 Session::set_global_record_enable (GlobalRouteBooleanState s, void* src)
2259 set_global_route_boolean (s, &Route::set_record_enable, src);
2263 accept_all_non_peak_files (const string& path, void *arg)
2265 return (path.length() > 5 && path.find (peakfile_suffix) != (path.length() - 5));
2269 accept_all_state_files (const string& path, void *arg)
2271 return (path.length() > 7 && path.find (".ardour") == (path.length() - 7));
2275 Session::find_all_sources (string path, set<string>& result)
2280 if (!tree.read (path)) {
2284 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2289 XMLNodeConstIterator niter;
2291 nlist = node->children();
2295 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2299 if ((prop = (*niter)->property (X_("name"))) == 0) {
2303 if (prop->value()[0] == '/') {
2304 /* external file, ignore */
2308 sys::path source_path = _session_dir->sound_path ();
2310 source_path /= prop->value ();
2312 result.insert (source_path.to_string ());
2319 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2321 PathScanner scanner;
2322 vector<string*>* state_files;
2324 string this_snapshot_path;
2330 if (ripped[ripped.length()-1] == '/') {
2331 ripped = ripped.substr (0, ripped.length() - 1);
2334 state_files = scanner (ripped, accept_all_state_files, (void *) 0, false, true);
2336 if (state_files == 0) {
2341 this_snapshot_path = _path;
2342 this_snapshot_path += _current_snapshot_name;
2343 this_snapshot_path += statefile_suffix;
2345 for (vector<string*>::iterator i = state_files->begin(); i != state_files->end(); ++i) {
2347 if (exclude_this_snapshot && **i == this_snapshot_path) {
2351 if (find_all_sources (**i, result) < 0) {
2359 struct RegionCounter {
2360 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2361 AudioSourceList::iterator iter;
2362 boost::shared_ptr<Region> region;
2365 RegionCounter() : count (0) {}
2369 Session::cleanup_sources (Session::cleanup_report& rep)
2371 // FIXME: needs adaptation to midi
2373 vector<boost::shared_ptr<Source> > dead_sources;
2374 vector<boost::shared_ptr<Playlist> > playlists_tbd;
2375 PathScanner scanner;
2377 vector<space_and_path>::iterator i;
2378 vector<space_and_path>::iterator nexti;
2379 vector<string*>* soundfiles;
2380 vector<string> unused;
2381 set<string> all_sources;
2386 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2389 /* step 1: consider deleting all unused playlists */
2391 for (PlaylistList::iterator x = unused_playlists.begin(); x != unused_playlists.end(); ++x) {
2394 status = AskAboutPlaylistDeletion (*x);
2403 playlists_tbd.push_back (*x);
2407 /* leave it alone */
2412 /* now delete any that were marked for deletion */
2414 for (vector<boost::shared_ptr<Playlist> >::iterator x = playlists_tbd.begin(); x != playlists_tbd.end(); ++x) {
2415 (*x)->drop_references ();
2418 playlists_tbd.clear ();
2420 /* step 2: find all un-used sources */
2425 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2427 SourceMap::iterator tmp;
2432 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2436 if (!i->second->used() && i->second->length(i->second->timeline_position()) > 0) {
2437 dead_sources.push_back (i->second);
2438 i->second->GoingAway();
2444 /* build a list of all the possible sound directories for the session */
2446 for (i = session_dirs.begin(); i != session_dirs.end(); ) {
2451 SessionDirectory sdir ((*i).path);
2452 sound_path += sdir.sound_path().to_string();
2454 if (nexti != session_dirs.end()) {
2461 /* now do the same thing for the files that ended up in the sounds dir(s)
2462 but are not referenced as sources in any snapshot.
2465 soundfiles = scanner (sound_path, accept_all_non_peak_files, (void *) 0, false, true);
2467 if (soundfiles == 0) {
2471 /* find all sources, but don't use this snapshot because the
2472 state file on disk still references sources we may have already
2476 find_all_sources_across_snapshots (all_sources, true);
2478 /* add our current source list
2481 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2482 boost::shared_ptr<FileSource> fs;
2484 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2485 all_sources.insert (fs->path());
2489 char tmppath1[PATH_MAX+1];
2490 char tmppath2[PATH_MAX+1];
2492 for (vector<string*>::iterator x = soundfiles->begin(); x != soundfiles->end(); ++x) {
2497 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2499 realpath(spath.c_str(), tmppath1);
2500 realpath((*i).c_str(), tmppath2);
2502 if (strcmp(tmppath1, tmppath2) == 0) {
2509 unused.push_back (spath);
2513 /* now try to move all unused files into the "dead_sounds" directory(ies) */
2515 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2516 struct stat statbuf;
2518 rep.paths.push_back (*x);
2519 if (stat ((*x).c_str(), &statbuf) == 0) {
2520 rep.space += statbuf.st_size;
2525 /* don't move the file across filesystems, just
2526 stick it in the `dead_sound_dir_name' directory
2527 on whichever filesystem it was already on.
2530 if ((*x).find ("/sounds/") != string::npos) {
2532 /* old school, go up 1 level */
2534 newpath = Glib::path_get_dirname (*x); // "sounds"
2535 newpath = Glib::path_get_dirname (newpath); // "session-name"
2539 /* new school, go up 4 levels */
2541 newpath = Glib::path_get_dirname (*x); // "audiofiles"
2542 newpath = Glib::path_get_dirname (newpath); // "session-name"
2543 newpath = Glib::path_get_dirname (newpath); // "interchange"
2544 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2548 newpath += dead_sound_dir_name;
2550 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2551 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2556 newpath += Glib::path_get_basename ((*x));
2558 if (access (newpath.c_str(), F_OK) == 0) {
2560 /* the new path already exists, try versioning */
2562 char buf[PATH_MAX+1];
2566 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2569 while (access (newpath_v.c_str(), F_OK) == 0 && version < 999) {
2570 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2574 if (version == 999) {
2575 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2579 newpath = newpath_v;
2584 /* it doesn't exist, or we can't read it or something */
2588 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2589 error << string_compose (_("cannot rename audio file source from %1 to %2 (%3)"),
2590 (*x), newpath, strerror (errno))
2595 /* see if there an easy to find peakfile for this file, and remove it.
2598 string peakpath = (*x).substr (0, (*x).find_last_of ('.'));
2599 peakpath += peakfile_suffix;
2601 if (access (peakpath.c_str(), W_OK) == 0) {
2602 if (::unlink (peakpath.c_str()) != 0) {
2603 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2604 peakpath, _path, strerror (errno))
2606 /* try to back out */
2607 rename (newpath.c_str(), _path.c_str());
2615 /* dump the history list */
2619 /* save state so we don't end up a session file
2620 referring to non-existent sources.
2626 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
2632 Session::cleanup_trash_sources (Session::cleanup_report& rep)
2634 // FIXME: needs adaptation for MIDI
2636 vector<space_and_path>::iterator i;
2637 string dead_sound_dir;
2638 struct dirent* dentry;
2639 struct stat statbuf;
2645 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2647 dead_sound_dir = (*i).path;
2648 dead_sound_dir += dead_sound_dir_name;
2650 if ((dead = opendir (dead_sound_dir.c_str())) == 0) {
2654 while ((dentry = readdir (dead)) != 0) {
2656 /* avoid '.' and '..' */
2658 if ((dentry->d_name[0] == '.' && dentry->d_name[1] == '\0') ||
2659 (dentry->d_name[2] == '\0' && dentry->d_name[0] == '.' && dentry->d_name[1] == '.')) {
2665 fullpath = dead_sound_dir;
2667 fullpath += dentry->d_name;
2669 if (stat (fullpath.c_str(), &statbuf)) {
2673 if (!S_ISREG (statbuf.st_mode)) {
2677 if (unlink (fullpath.c_str())) {
2678 error << string_compose (_("cannot remove dead sound file %1 (%2)"),
2679 fullpath, strerror (errno))
2683 rep.paths.push_back (dentry->d_name);
2684 rep.space += statbuf.st_size;
2695 Session::set_dirty ()
2697 bool was_dirty = dirty();
2699 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
2703 DirtyChanged(); /* EMIT SIGNAL */
2709 Session::set_clean ()
2711 bool was_dirty = dirty();
2713 _state_of_the_state = Clean;
2717 DirtyChanged(); /* EMIT SIGNAL */
2722 Session::set_deletion_in_progress ()
2724 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
2728 Session::clear_deletion_in_progress ()
2730 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
2734 Session::add_controllable (boost::shared_ptr<Controllable> c)
2736 /* this adds a controllable to the list managed by the Session.
2737 this is a subset of those managed by the Controllable class
2738 itself, and represents the only ones whose state will be saved
2739 as part of the session.
2742 Glib::Mutex::Lock lm (controllables_lock);
2743 controllables.insert (c);
2746 struct null_deleter { void operator()(void const *) const {} };
2749 Session::remove_controllable (Controllable* c)
2751 if (_state_of_the_state | Deletion) {
2755 Glib::Mutex::Lock lm (controllables_lock);
2757 Controllables::iterator x = controllables.find(
2758 boost::shared_ptr<Controllable>(c, null_deleter()));
2760 if (x != controllables.end()) {
2761 controllables.erase (x);
2765 boost::shared_ptr<Controllable>
2766 Session::controllable_by_id (const PBD::ID& id)
2768 Glib::Mutex::Lock lm (controllables_lock);
2770 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
2771 if ((*i)->id() == id) {
2776 return boost::shared_ptr<Controllable>();
2780 Session::add_instant_xml (XMLNode& node, bool write_to_config)
2782 Stateful::add_instant_xml (node, _path);
2783 if (write_to_config) {
2784 Config->add_instant_xml (node);
2789 Session::instant_xml (const string& node_name)
2791 return Stateful::instant_xml (node_name, _path);
2795 Session::save_history (string snapshot_name)
2799 if (snapshot_name.empty()) {
2800 snapshot_name = _current_snapshot_name;
2803 const string history_filename = snapshot_name + history_suffix;
2804 const string backup_filename = history_filename + backup_suffix;
2805 const sys::path xml_path = _session_dir->root_path() / history_filename;
2806 const sys::path backup_path = _session_dir->root_path() / backup_filename;
2808 if (sys::exists (xml_path)) {
2811 sys::rename (xml_path, backup_path);
2813 catch (const sys::filesystem_error& err)
2815 error << _("could not backup old history file, current history not saved") << endmsg;
2821 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0) {
2825 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
2827 if (!tree.write (xml_path.to_string()))
2829 error << string_compose (_("history could not be saved to %1"), xml_path.to_string()) << endmsg;
2833 sys::remove (xml_path);
2834 sys::rename (backup_path, xml_path);
2836 catch (const sys::filesystem_error& err)
2838 error << string_compose (_("could not restore history file from backup %1 (%2)"),
2839 backup_path.to_string(), err.what()) << endmsg;
2849 Session::restore_history (string snapshot_name)
2853 if (snapshot_name.empty()) {
2854 snapshot_name = _current_snapshot_name;
2857 const string xml_filename = snapshot_name + history_suffix;
2858 const sys::path xml_path = _session_dir->root_path() / xml_filename;
2860 cerr << "Loading history from " << xml_path.to_string() << endmsg;
2862 if (!sys::exists (xml_path)) {
2863 info << string_compose (_("%1: no history file \"%2\" for this session."),
2864 _name, xml_path.to_string()) << endmsg;
2868 if (!tree.read (xml_path.to_string())) {
2869 error << string_compose (_("Could not understand session history file \"%1\""),
2870 xml_path.to_string()) << endmsg;
2877 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
2880 UndoTransaction* ut = new UndoTransaction ();
2883 ut->set_name(t->property("name")->value());
2884 stringstream ss(t->property("tv-sec")->value());
2886 ss.str(t->property("tv-usec")->value());
2888 ut->set_timestamp(tv);
2890 for (XMLNodeConstIterator child_it = t->children().begin();
2891 child_it != t->children().end(); child_it++)
2893 XMLNode *n = *child_it;
2896 if (n->name() == "MementoCommand" ||
2897 n->name() == "MementoUndoCommand" ||
2898 n->name() == "MementoRedoCommand") {
2900 if ((c = memento_command_factory(n))) {
2904 } else if (n->name() == X_("GlobalRouteStateCommand")) {
2906 if ((c = global_state_command_factory (*n))) {
2907 ut->add_command (c);
2910 } else if (n->name() == "DeltaCommand") {
2911 PBD::ID id(n->property("midi-source")->value());
2912 boost::shared_ptr<MidiSource> midi_source =
2913 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
2915 ut->add_command(new MidiModel::DeltaCommand(midi_source->model(), *n));
2917 error << "FIXME: Failed to downcast MidiSource for DeltaCommand" << endmsg;
2920 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
2931 Session::config_changed (std::string p, bool ours)
2937 if (p == "seamless-loop") {
2939 } else if (p == "rf-speed") {
2941 } else if (p == "auto-loop") {
2943 } else if (p == "auto-input") {
2945 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
2946 /* auto-input only makes a difference if we're rolling */
2948 boost::shared_ptr<DiskstreamList> dsl = diskstreams.reader();
2950 for (DiskstreamList::iterator i = dsl->begin(); i != dsl->end(); ++i) {
2951 if ((*i)->record_enabled ()) {
2952 (*i)->monitor_input (!config.get_auto_input());
2957 } else if (p == "punch-in") {
2961 if ((location = _locations.auto_punch_location()) != 0) {
2963 if (config.get_punch_in ()) {
2964 replace_event (Event::PunchIn, location->start());
2966 remove_event (location->start(), Event::PunchIn);
2970 } else if (p == "punch-out") {
2974 if ((location = _locations.auto_punch_location()) != 0) {
2976 if (config.get_punch_out()) {
2977 replace_event (Event::PunchOut, location->end());
2979 clear_events (Event::PunchOut);
2983 } else if (p == "edit-mode") {
2985 Glib::Mutex::Lock lm (playlist_lock);
2987 for (PlaylistList::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2988 (*i)->set_edit_mode (Config->get_edit_mode ());
2991 } else if (p == "use-video-sync") {
2993 waiting_for_sync_offset = config.get_use_video_sync();
2995 } else if (p == "mmc-control") {
2997 //poke_midi_thread ();
2999 } else if (p == "mmc-device-id" || p == "mmc-receive-id") {
3002 mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3005 } else if (p == "mmc-send-id") {
3008 mmc->set_send_device_id (Config->get_mmc_send_device_id());
3011 } else if (p == "midi-control") {
3013 //poke_midi_thread ();
3015 } else if (p == "raid-path") {
3017 setup_raid_path (config.get_raid_path());
3019 } else if (p == "smpte-format") {
3023 } else if (p == "video-pullup") {
3027 } else if (p == "seamless-loop") {
3029 if (play_loop && transport_rolling()) {
3030 // to reset diskstreams etc
3031 request_play_loop (true);
3034 } else if (p == "rf-speed") {
3036 cumulative_rf_motion = 0;
3039 } else if (p == "click-sound") {
3041 setup_click_sounds (1);
3043 } else if (p == "click-emphasis-sound") {
3045 setup_click_sounds (-1);
3047 } else if (p == "clicking") {
3049 if (Config->get_clicking()) {
3050 if (_click_io && click_data) { // don't require emphasis data
3057 } else if (p == "send-mtc") {
3059 /* only set the internal flag if we have
3063 if (_mtc_port != 0) {
3064 session_send_mtc = Config->get_send_mtc();
3065 if (session_send_mtc) {
3066 /* mark us ready to send */
3067 next_quarter_frame_to_send = 0;
3070 session_send_mtc = false;
3073 } else if (p == "send-mmc") {
3075 /* only set the internal flag if we have
3079 if (_mmc_port != 0) {
3080 session_send_mmc = Config->get_send_mmc();
3083 session_send_mmc = false;
3086 } else if (p == "midi-feedback") {
3088 /* only set the internal flag if we have
3092 if (_mtc_port != 0) {
3093 session_midi_feedback = Config->get_midi_feedback();
3096 } else if (p == "jack-time-master") {
3098 engine().reset_timebase ();
3100 } else if (p == "native-file-header-format") {
3102 if (!first_file_header_format_reset) {
3103 reset_native_file_format ();
3106 first_file_header_format_reset = false;
3108 } else if (p == "native-file-data-format") {
3110 if (!first_file_data_format_reset) {
3111 reset_native_file_format ();
3114 first_file_data_format_reset = false;
3116 } else if (p == "slave-source") {
3117 set_slave_source (Config->get_slave_source());
3118 } else if (p == "remote-model") {
3119 set_remote_control_ids ();
3120 } else if (p == "denormal-model") {
3122 } else if (p == "history-depth") {
3123 set_history_depth (Config->get_history_depth());
3124 } else if (p == "sync-all-route-ordering") {
3125 sync_order_keys ("session");
3126 } else if (p == "initial-program-change") {
3128 if (_mmc_port && Config->get_initial_program_change() >= 0) {
3131 buf[0] = MIDI::program; // channel zero by default
3132 buf[1] = (Config->get_initial_program_change() & 0x7f);
3134 _mmc_port->midimsg (buf, sizeof (buf), 0);
3136 } else if (p == "initial-program-change") {
3138 if (_mmc_port && Config->get_initial_program_change() >= 0) {
3139 MIDI::byte* buf = new MIDI::byte[2];
3141 buf[0] = MIDI::program; // channel zero by default
3142 buf[1] = (Config->get_initial_program_change() & 0x7f);
3143 // deliver_midi (_mmc_port, buf, 2);
3145 } else if (p == "solo-mute-override") {
3146 // catch_up_on_solo_mute_override ();
3147 } else if (p == "solo-model") {
3148 solo_model_changed ();
3155 Session::set_history_depth (uint32_t d)
3157 _history.set_depth (d);