2 Copyright (C) 1999-2013 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.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/session.h"
118 #include "ardour/session_directory.h"
119 #include "ardour/session_metadata.h"
120 #include "ardour/session_playlists.h"
121 #include "ardour/session_state_utils.h"
122 #include "ardour/silentfilesource.h"
123 #include "ardour/sndfilesource.h"
124 #include "ardour/source_factory.h"
125 #include "ardour/speakers.h"
126 #include "ardour/template_utils.h"
127 #include "ardour/tempo.h"
128 #include "ardour/ticker.h"
129 #include "ardour/user_bundle.h"
130 #include "ardour/vca.h"
131 #include "ardour/vca_manager.h"
133 #include "control_protocol/control_protocol.h"
135 #include "LuaBridge/LuaBridge.h"
137 #include "pbd/i18n.h"
141 using namespace ARDOUR;
144 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
147 Session::pre_engine_init (string fullpath)
149 if (fullpath.empty()) {
151 throw failed_constructor();
154 /* discover canonical fullpath */
156 _path = canonical_path(fullpath);
159 if (Profile->get_trx() ) {
160 // Waves TracksLive has a usecase of session replacement with a new one.
161 // We should check session state file (<session_name>.ardour) existance
162 // to determine if the session is new or not
164 string full_session_name = Glib::build_filename( fullpath, _name );
165 full_session_name += statefile_suffix;
167 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
169 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
172 /* finish initialization that can't be done in a normal C++ constructor
176 timerclear (&last_mmc_step);
177 g_atomic_int_set (&processing_prohibited, 0);
178 g_atomic_int_set (&_record_status, Disabled);
179 g_atomic_int_set (&_playback_load, 100);
180 g_atomic_int_set (&_capture_load, 100);
182 _all_route_group->set_active (true, this);
183 interpolation.add_channel_to (0, 0);
185 if (config.get_use_video_sync()) {
186 waiting_for_sync_offset = true;
188 waiting_for_sync_offset = false;
191 last_rr_session_dir = session_dirs.begin();
193 set_history_depth (Config->get_history_depth());
195 /* default: assume simple stereo speaker configuration */
197 _speakers->setup_default_speakers (2);
199 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
200 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
201 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
202 add_controllable (_solo_cut_control);
204 /* These are all static "per-class" signals */
206 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
207 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
208 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
209 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
210 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
212 /* stop IO objects from doing stuff until we're ready for them */
214 Delivery::disable_panners ();
215 IO::disable_connecting ();
219 Session::post_engine_init ()
221 BootMessage (_("Set block size and sample rate"));
223 set_block_size (_engine.samples_per_cycle());
224 set_frame_rate (_engine.sample_rate());
226 BootMessage (_("Using configuration"));
228 _midi_ports = new MidiPortManager;
230 MIDISceneChanger* msc;
232 _scene_changer = msc = new MIDISceneChanger (*this);
233 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
234 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
236 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
237 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
239 setup_midi_machine_control ();
241 if (_butler->start_thread()) {
242 error << _("Butler did not start") << endmsg;
246 if (start_midi_thread ()) {
247 error << _("MIDI I/O thread did not start") << endmsg;
251 setup_click_sounds (0);
252 setup_midi_control ();
254 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
255 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
258 /* tempo map requires sample rate knowledge */
261 _tempo_map = new TempoMap (_current_frame_rate);
262 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
263 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
265 /* MidiClock requires a tempo map */
268 midi_clock = new MidiClockTicker ();
269 midi_clock->set_session (this);
271 /* crossfades require sample rate knowledge */
273 SndFileSource::setup_standard_crossfades (*this, frame_rate());
274 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
275 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
277 AudioDiskstream::allocate_working_buffers();
278 refresh_disk_space ();
280 /* we're finally ready to call set_state() ... all objects have
281 * been created, the engine is running.
285 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
286 error << _("Could not set session state from XML") << endmsg;
290 // set_state() will call setup_raid_path(), but if it's a new session we need
291 // to call setup_raid_path() here.
292 setup_raid_path (_path);
297 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
298 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
300 Config->map_parameters (ff);
301 config.map_parameters (ft);
302 _butler->map_parameters ();
304 /* Reset all panners */
306 Delivery::reset_panners ();
308 /* this will cause the CPM to instantiate any protocols that are in use
309 * (or mandatory), which will pass it this Session, and then call
310 * set_state() on each instantiated protocol to match stored state.
313 ControlProtocolManager::instance().set_session (this);
315 /* This must be done after the ControlProtocolManager set_session above,
316 as it will set states for ports which the ControlProtocolManager creates.
319 // XXX set state of MIDI::Port's
320 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
322 /* And this must be done after the MIDI::Manager::set_port_states as
323 * it will try to make connections whose details are loaded by set_port_states.
328 /* Let control protocols know that we are now all connected, so they
329 * could start talking to surfaces if they want to.
332 ControlProtocolManager::instance().midi_connectivity_established ();
334 if (_is_new && !no_auto_connect()) {
335 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
336 auto_connect_master_bus ();
339 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
341 /* update latencies */
343 initialize_latencies ();
345 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
346 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
347 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
349 } catch (AudioEngine::PortRegistrationFailure& err) {
350 /* handle this one in a different way than all others, so that its clear what happened */
351 error << err.what() << endmsg;
353 } catch (std::exception const & e) {
354 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
357 error << _("Unknown exception during session setup") << endmsg;
361 BootMessage (_("Reset Remote Controls"));
363 // send_full_time_code (0);
364 _engine.transport_locate (0);
366 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
367 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
369 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
372 /* initial program change will be delivered later; see ::config_changed() */
374 _state_of_the_state = Clean;
376 Port::set_connecting_blocked (false);
378 DirtyChanged (); /* EMIT SIGNAL */
382 } else if (state_was_pending) {
384 remove_pending_capture_state ();
385 state_was_pending = false;
388 /* Now, finally, we can fill the playback buffers */
390 BootMessage (_("Filling playback buffers"));
392 boost::shared_ptr<RouteList> rl = routes.reader();
393 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
394 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
395 if (trk && !trk->hidden()) {
396 trk->seek (_transport_frame, true);
404 Session::session_loaded ()
408 _state_of_the_state = Clean;
410 DirtyChanged (); /* EMIT SIGNAL */
414 } else if (state_was_pending) {
416 remove_pending_capture_state ();
417 state_was_pending = false;
420 /* Now, finally, we can fill the playback buffers */
422 BootMessage (_("Filling playback buffers"));
423 force_locate (_transport_frame, false);
427 Session::raid_path () const
429 Searchpath raid_search_path;
431 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
432 raid_search_path += (*i).path;
435 return raid_search_path.to_string ();
439 Session::setup_raid_path (string path)
448 session_dirs.clear ();
450 Searchpath search_path(path);
451 Searchpath sound_search_path;
452 Searchpath midi_search_path;
454 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
456 sp.blocks = 0; // not needed
457 session_dirs.push_back (sp);
459 SessionDirectory sdir(sp.path);
461 sound_search_path += sdir.sound_path ();
462 midi_search_path += sdir.midi_path ();
465 // reset the round-robin soundfile path thingie
466 last_rr_session_dir = session_dirs.begin();
470 Session::path_is_within_session (const std::string& path)
472 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
473 if (PBD::path_is_within (i->path, path)) {
481 Session::ensure_subdirs ()
485 dir = session_directory().peak_path();
487 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
488 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
492 dir = session_directory().sound_path();
494 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
495 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
499 dir = session_directory().midi_path();
501 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
502 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 dir = session_directory().dead_path();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = session_directory().export_path();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
520 dir = analysis_dir ();
522 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
523 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
527 dir = plugins_dir ();
529 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
534 dir = externals_dir ();
536 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
537 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
544 /** @param session_template directory containing session template, or empty.
545 * Caller must not hold process lock.
548 Session::create (const string& session_template, BusProfile* bus_profile)
550 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
551 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
555 if (ensure_subdirs ()) {
559 _writable = exists_and_writable (_path);
561 if (!session_template.empty()) {
562 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
564 FILE* in = g_fopen (in_path.c_str(), "rb");
567 /* no need to call legalize_for_path() since the string
568 * in session_template is already a legal path name
570 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
572 FILE* out = g_fopen (out_path.c_str(), "wb");
576 stringstream new_session;
579 size_t charsRead = fread (buf, sizeof(char), 1024, in);
582 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
587 if (charsRead == 0) {
590 new_session.write (buf, charsRead);
594 string file_contents = new_session.str();
595 size_t writeSize = file_contents.length();
596 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
597 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
605 if (!ARDOUR::Profile->get_trx()) {
606 /* Copy plugin state files from template to new session */
607 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
608 copy_recurse (template_plugins, plugins_dir ());
614 error << string_compose (_("Could not open %1 for writing session template"), out_path)
621 error << string_compose (_("Could not open session template %1 for reading"), in_path)
628 if (Profile->get_trx()) {
630 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
631 Remember that this is a brand new session. Sessions
632 loaded from saved state will get this range from the saved state.
635 set_session_range_location (0, 0);
637 /* Initial loop location, from absolute zero, length 10 seconds */
639 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
640 _locations->add (loc, true);
641 set_auto_loop_location (loc);
644 _state_of_the_state = Clean;
646 /* set up Master Out and Monitor Out if necessary */
651 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
653 // Waves Tracks: always create master bus for Tracks
654 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
655 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
663 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
664 r->input()->ensure_io (count, false, this);
665 r->output()->ensure_io (count, false, this);
671 /* prohibit auto-connect to master, because there isn't one */
672 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
676 add_routes (rl, false, false, false, PresentationInfo::max_order);
679 // Waves Tracks: Skip this. Always use autoconnection for Tracks
680 if (!ARDOUR::Profile->get_trx()) {
682 /* this allows the user to override settings with an environment variable.
685 if (no_auto_connect()) {
686 bus_profile->input_ac = AutoConnectOption (0);
687 bus_profile->output_ac = AutoConnectOption (0);
690 Config->set_input_auto_connect (bus_profile->input_ac);
691 Config->set_output_auto_connect (bus_profile->output_ac);
695 if (Config->get_use_monitor_bus() && bus_profile) {
696 add_monitor_section ();
703 Session::maybe_write_autosave()
705 if (dirty() && record_status() != Recording) {
706 save_state("", true);
711 Session::remove_pending_capture_state ()
713 std::string pending_state_file_path(_session_dir->root_path());
715 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
717 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
719 if (g_remove (pending_state_file_path.c_str()) != 0) {
720 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
721 pending_state_file_path, g_strerror (errno)) << endmsg;
725 /** Rename a state file.
726 * @param old_name Old snapshot name.
727 * @param new_name New snapshot name.
730 Session::rename_state (string old_name, string new_name)
732 if (old_name == _current_snapshot_name || old_name == _name) {
733 /* refuse to rename the current snapshot or the "main" one */
737 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
738 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
740 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
741 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
743 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
744 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
745 old_name, new_name, g_strerror(errno)) << endmsg;
749 /** Remove a state file.
750 * @param snapshot_name Snapshot name.
753 Session::remove_state (string snapshot_name)
755 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
756 // refuse to remove the current snapshot or the "main" one
760 std::string xml_path(_session_dir->root_path());
762 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
764 if (!create_backup_file (xml_path)) {
765 // don't remove it if a backup can't be made
766 // create_backup_file will log the error.
771 if (g_remove (xml_path.c_str()) != 0) {
772 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
773 xml_path, g_strerror (errno)) << endmsg;
777 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
779 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
781 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
784 std::string xml_path(_session_dir->root_path());
786 /* prevent concurrent saves from different threads */
788 Glib::Threads::Mutex::Lock lm (save_state_lock);
790 if (!_writable || (_state_of_the_state & CannotSave)) {
794 if (g_atomic_int_get(&_suspend_save)) {
798 _save_queued = false;
800 if (!_engine.connected ()) {
801 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
808 const int64_t save_start_time = g_get_monotonic_time();
811 /* tell sources we're saving first, in case they write out to a new file
812 * which should be saved with the state rather than the old one */
813 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
815 i->second->session_saved();
816 } catch (Evoral::SMF::FileError& e) {
817 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
821 SessionSaveUnderway (); /* EMIT SIGNAL */
823 bool mark_as_clean = true;
825 if (!snapshot_name.empty() && !switch_to_snapshot) {
826 mark_as_clean = false;
830 mark_as_clean = false;
831 tree.set_root (&get_template());
833 tree.set_root (&get_state());
836 if (snapshot_name.empty()) {
837 snapshot_name = _current_snapshot_name;
838 } else if (switch_to_snapshot) {
839 set_snapshot_name (snapshot_name);
842 assert (!snapshot_name.empty());
846 /* proper save: use statefile_suffix (.ardour in English) */
848 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
850 /* make a backup copy of the old file */
852 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
853 // create_backup_file will log the error
859 /* pending save: use pending_suffix (.pending in English) */
860 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
863 std::string tmp_path(_session_dir->root_path());
864 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
866 cerr << "actually writing state to " << tmp_path << endl;
868 if (!tree.write (tmp_path)) {
869 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
870 if (g_remove (tmp_path.c_str()) != 0) {
871 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
872 tmp_path, g_strerror (errno)) << endmsg;
878 cerr << "renaming state to " << xml_path << endl;
880 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
881 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
882 tmp_path, xml_path, g_strerror(errno)) << endmsg;
883 if (g_remove (tmp_path.c_str()) != 0) {
884 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
885 tmp_path, g_strerror (errno)) << endmsg;
893 save_history (snapshot_name);
896 bool was_dirty = dirty();
898 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
901 DirtyChanged (); /* EMIT SIGNAL */
905 StateSaved (snapshot_name); /* EMIT SIGNAL */
909 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
910 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
916 Session::restore_state (string snapshot_name)
918 if (load_state (snapshot_name) == 0) {
919 set_state (*state_tree->root(), Stateful::loading_state_version);
926 Session::load_state (string snapshot_name)
931 state_was_pending = false;
933 /* check for leftover pending state from a crashed capture attempt */
935 std::string xmlpath(_session_dir->root_path());
936 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
938 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
940 /* there is pending state from a crashed capture attempt */
942 boost::optional<int> r = AskAboutPendingState();
943 if (r.get_value_or (1)) {
944 state_was_pending = true;
948 if (!state_was_pending) {
949 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
952 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
953 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
954 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
955 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
960 state_tree = new XMLTree;
964 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
966 if (!state_tree->read (xmlpath)) {
967 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
973 XMLNode const & root (*state_tree->root());
975 if (root.name() != X_("Session")) {
976 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
982 XMLProperty const * prop;
984 if ((prop = root.property ("version")) == 0) {
985 /* no version implies very old version of Ardour */
986 Stateful::loading_state_version = 1000;
988 if (prop->value().find ('.') != string::npos) {
989 /* old school version format */
990 if (prop->value()[0] == '2') {
991 Stateful::loading_state_version = 2000;
993 Stateful::loading_state_version = 3000;
996 Stateful::loading_state_version = atoi (prop->value());
1000 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1002 std::string backup_path(_session_dir->root_path());
1003 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1004 backup_path = Glib::build_filename (backup_path, backup_filename);
1006 // only create a backup for a given statefile version once
1008 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1010 VersionMismatch (xmlpath, backup_path);
1012 if (!copy_file (xmlpath, backup_path)) {;
1018 save_snapshot_name (snapshot_name);
1024 Session::load_options (const XMLNode& node)
1027 config.set_variables (node);
1032 Session::save_default_options ()
1034 return config.save_state();
1038 Session::get_state()
1044 Session::get_template()
1046 /* if we don't disable rec-enable, diskstreams
1047 will believe they need to store their capture
1048 sources in their state node.
1051 disable_record (false);
1053 return state(false);
1056 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1057 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1060 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1062 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1065 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1069 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1072 XMLNode* node = new XMLNode("TrackState"); // XXX
1075 PlaylistSet playlists; // SessionPlaylists
1078 // these will work with new_route_from_template()
1079 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1080 child = node->add_child ("Routes");
1081 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1082 if ((*i)->is_auditioner()) {
1085 if ((*i)->is_master() || (*i)->is_monitor()) {
1088 child->add_child_nocopy ((*i)->get_state());
1089 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1091 playlists.insert (track->playlist ());
1095 // on load, Regions in the playlists need to resolve and map Source-IDs
1096 // also playlist needs to be merged or created with new-name..
1097 // ... and Diskstream in tracks adjusted to use the correct playlist
1098 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1099 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1100 child->add_child_nocopy ((*i)->get_state ());
1101 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1102 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1103 const Region::SourceList& sl = (*s)->sources ();
1104 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1105 sources.insert (*sli);
1110 child = node->add_child ("Sources");
1111 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1112 child->add_child_nocopy ((*i)->get_state ());
1113 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1115 #ifdef PLATFORM_WINDOWS
1118 string p = fs->path ();
1119 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1123 std::string sn = Glib::build_filename (path, "share.axml");
1126 tree.set_root (node);
1127 return tree.write (sn.c_str());
1131 Session::state (bool full_state)
1134 XMLNode* node = new XMLNode("Session");
1138 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1139 node->add_property("version", buf);
1141 child = node->add_child ("ProgramVersion");
1142 child->add_property("created-with", created_with);
1144 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1145 child->add_property("modified-with", modified_with);
1147 /* store configuration settings */
1151 node->add_property ("name", _name);
1152 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1153 node->add_property ("sample-rate", buf);
1155 if (session_dirs.size() > 1) {
1159 vector<space_and_path>::iterator i = session_dirs.begin();
1160 vector<space_and_path>::iterator next;
1162 ++i; /* skip the first one */
1166 while (i != session_dirs.end()) {
1170 if (next != session_dirs.end()) {
1171 p += G_SEARCHPATH_SEPARATOR;
1180 child = node->add_child ("Path");
1181 child->add_content (p);
1185 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1187 /* save the ID counter */
1189 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1190 node->add_property ("id-counter", buf);
1192 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1193 node->add_property ("name-counter", buf);
1195 /* save the event ID counter */
1197 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1198 node->add_property ("event-counter", buf);
1200 /* save the VCA counter */
1202 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1203 node->add_property ("vca-counter", buf);
1205 /* various options */
1207 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1208 if (!midi_port_nodes.empty()) {
1209 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1210 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1211 midi_port_stuff->add_child_nocopy (**n);
1213 node->add_child_nocopy (*midi_port_stuff);
1216 XMLNode& cfgxml (config.get_variables ());
1218 /* exclude search-paths from template */
1219 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1220 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1221 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1223 node->add_child_nocopy (cfgxml);
1225 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1227 child = node->add_child ("Sources");
1230 Glib::Threads::Mutex::Lock sl (source_lock);
1232 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1234 /* Don't save information about non-file Sources, or
1235 * about non-destructive file sources that are empty
1236 * and unused by any regions.
1239 boost::shared_ptr<FileSource> fs;
1241 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1243 if (!fs->destructive()) {
1244 if (fs->empty() && !fs->used()) {
1249 child->add_child_nocopy (siter->second->get_state());
1254 child = node->add_child ("Regions");
1257 Glib::Threads::Mutex::Lock rl (region_lock);
1258 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1259 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1260 boost::shared_ptr<Region> r = i->second;
1261 /* only store regions not attached to playlists */
1262 if (r->playlist() == 0) {
1263 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1264 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1266 child->add_child_nocopy (r->get_state ());
1271 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1273 if (!cassocs.empty()) {
1274 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1276 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1277 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1278 can->add_property (X_("copy"), i->first->id().to_s());
1279 can->add_property (X_("original"), i->second->id().to_s());
1280 ca->add_child_nocopy (*can);
1290 node->add_child_nocopy (_locations->get_state());
1293 Locations loc (*this);
1294 const bool was_dirty = dirty();
1295 // for a template, just create a new Locations, populate it
1296 // with the default start and end, and get the state for that.
1297 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1298 range->set (max_framepos, 0);
1300 XMLNode& locations_state = loc.get_state();
1302 if (ARDOUR::Profile->get_trx() && _locations) {
1303 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1304 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1305 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1306 locations_state.add_child_nocopy ((*i)->get_state ());
1310 node->add_child_nocopy (locations_state);
1312 /* adding a location above will have marked the session
1313 * dirty. This is an artifact, so fix it if the session wasn't
1318 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1322 child = node->add_child ("Bundles");
1324 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1325 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1326 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1328 child->add_child_nocopy (b->get_state());
1333 node->add_child_nocopy (_vca_manager->get_state());
1335 child = node->add_child ("Routes");
1337 boost::shared_ptr<RouteList> r = routes.reader ();
1339 RoutePublicOrderSorter cmp;
1340 RouteList public_order (*r);
1341 public_order.sort (cmp);
1343 /* the sort should have put the monitor out first */
1346 assert (_monitor_out == public_order.front());
1349 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1350 if (!(*i)->is_auditioner()) {
1352 child->add_child_nocopy ((*i)->get_state());
1354 child->add_child_nocopy ((*i)->get_template());
1360 playlists->add_state (node, full_state);
1362 child = node->add_child ("RouteGroups");
1363 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1364 child->add_child_nocopy ((*i)->get_state());
1368 XMLNode* gain_child = node->add_child ("Click");
1369 gain_child->add_child_nocopy (_click_io->state (full_state));
1370 gain_child->add_child_nocopy (_click_gain->state (full_state));
1374 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1375 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1379 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1380 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1383 node->add_child_nocopy (_speakers->get_state());
1384 node->add_child_nocopy (_tempo_map->get_state());
1385 node->add_child_nocopy (get_control_protocol_state());
1388 node->add_child_copy (*_extra_xml);
1392 Glib::Threads::Mutex::Lock lm (lua_lock);
1395 luabridge::LuaRef savedstate ((*_lua_save)());
1396 saved = savedstate.cast<std::string>();
1398 lua.collect_garbage ();
1401 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1402 std::string b64s (b64);
1405 XMLNode* script_node = new XMLNode (X_("Script"));
1406 script_node->add_property (X_("lua"), LUA_VERSION);
1407 script_node->add_content (b64s);
1408 node->add_child_nocopy (*script_node);
1415 Session::get_control_protocol_state ()
1417 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1418 return cpm.get_state();
1422 Session::set_state (const XMLNode& node, int version)
1427 XMLProperty const * prop;
1430 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1432 if (node.name() != X_("Session")) {
1433 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1437 if ((prop = node.property ("name")) != 0) {
1438 _name = prop->value ();
1441 if ((prop = node.property (X_("sample-rate"))) != 0) {
1443 _base_frame_rate = atoi (prop->value());
1444 _nominal_frame_rate = _base_frame_rate;
1446 assert (AudioEngine::instance()->running ());
1447 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1448 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1449 if (r.get_value_or (0)) {
1455 created_with = "unknown";
1456 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1457 if ((prop = child->property (X_("created-with"))) != 0) {
1458 created_with = prop->value ();
1462 setup_raid_path(_session_dir->root_path());
1464 if ((prop = node.property (X_("end-is-free"))) != 0) {
1465 _session_range_end_is_free = string_is_affirmative (prop->value());
1468 if ((prop = node.property (X_("id-counter"))) != 0) {
1470 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1471 ID::init_counter (x);
1473 /* old sessions used a timebased counter, so fake
1474 the startup ID counter based on a standard
1479 ID::init_counter (now);
1482 if ((prop = node.property (X_("name-counter"))) != 0) {
1483 init_name_id_counter (atoi (prop->value()));
1486 if ((prop = node.property (X_("event-counter"))) != 0) {
1487 Evoral::init_event_id_counter (atoi (prop->value()));
1490 if ((prop = node.property (X_("vca-counter"))) != 0) {
1492 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1493 VCA::set_next_vca_number (x);
1495 VCA::set_next_vca_number (1);
1498 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1499 _midi_ports->set_midi_port_states (child->children());
1502 IO::disable_connecting ();
1504 Stateful::save_extra_xml (node);
1506 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1507 load_options (*child);
1508 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1509 load_options (*child);
1511 error << _("Session: XML state has no options section") << endmsg;
1514 if (version >= 3000) {
1515 if ((child = find_named_node (node, "Metadata")) == 0) {
1516 warning << _("Session: XML state has no metadata section") << endmsg;
1517 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1522 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1523 _speakers->set_state (*child, version);
1526 if ((child = find_named_node (node, "Sources")) == 0) {
1527 error << _("Session: XML state has no sources section") << endmsg;
1529 } else if (load_sources (*child)) {
1533 if ((child = find_named_node (node, "TempoMap")) == 0) {
1534 error << _("Session: XML state has no Tempo Map section") << endmsg;
1536 } else if (_tempo_map->set_state (*child, version)) {
1540 if ((child = find_named_node (node, "Locations")) == 0) {
1541 error << _("Session: XML state has no locations section") << endmsg;
1543 } else if (_locations->set_state (*child, version)) {
1547 locations_changed ();
1549 if (_session_range_location) {
1550 AudioFileSource::set_header_position_offset (_session_range_location->start());
1553 if ((child = find_named_node (node, "Regions")) == 0) {
1554 error << _("Session: XML state has no Regions section") << endmsg;
1556 } else if (load_regions (*child)) {
1560 if ((child = find_named_node (node, "Playlists")) == 0) {
1561 error << _("Session: XML state has no playlists section") << endmsg;
1563 } else if (playlists->load (*this, *child)) {
1567 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1569 } else if (playlists->load_unused (*this, *child)) {
1573 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1574 if (load_compounds (*child)) {
1579 if (version >= 3000) {
1580 if ((child = find_named_node (node, "Bundles")) == 0) {
1581 warning << _("Session: XML state has no bundles section") << endmsg;
1584 /* We can't load Bundles yet as they need to be able
1585 to convert from port names to Port objects, which can't happen until
1587 _bundle_xml_node = new XMLNode (*child);
1591 if (version < 3000) {
1592 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1593 error << _("Session: XML state has no diskstreams section") << endmsg;
1595 } else if (load_diskstreams_2X (*child, version)) {
1600 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1601 _vca_manager->set_state (*child, version);
1604 if ((child = find_named_node (node, "Routes")) == 0) {
1605 error << _("Session: XML state has no routes section") << endmsg;
1607 } else if (load_routes (*child, version)) {
1611 /* Now that we have Routes and masters loaded, connect them if appropriate */
1613 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1615 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1616 _diskstreams_2X.clear ();
1618 if (version >= 3000) {
1620 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1621 error << _("Session: XML state has no route groups section") << endmsg;
1623 } else if (load_route_groups (*child, version)) {
1627 } else if (version < 3000) {
1629 if ((child = find_named_node (node, "EditGroups")) == 0) {
1630 error << _("Session: XML state has no edit groups section") << endmsg;
1632 } else if (load_route_groups (*child, version)) {
1636 if ((child = find_named_node (node, "MixGroups")) == 0) {
1637 error << _("Session: XML state has no mix groups section") << endmsg;
1639 } else if (load_route_groups (*child, version)) {
1644 if ((child = find_named_node (node, "Click")) == 0) {
1645 warning << _("Session: XML state has no click section") << endmsg;
1646 } else if (_click_io) {
1647 setup_click_state (&node);
1650 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1651 ControlProtocolManager::instance().set_state (*child, version);
1654 if ((child = find_named_node (node, "Script"))) {
1655 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1656 if (!(*n)->is_content ()) { continue; }
1658 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1660 Glib::Threads::Mutex::Lock lm (lua_lock);
1661 (*_lua_load)(std::string ((const char*)buf, size));
1662 } catch (luabridge::LuaException const& e) {
1663 cerr << "LuaException:" << e.what () << endl;
1669 update_route_record_state ();
1671 /* here beginneth the second phase ... */
1672 set_snapshot_name (_current_snapshot_name);
1674 StateReady (); /* EMIT SIGNAL */
1687 Session::load_routes (const XMLNode& node, int version)
1690 XMLNodeConstIterator niter;
1691 RouteList new_routes;
1693 nlist = node.children();
1697 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1699 boost::shared_ptr<Route> route;
1700 if (version < 3000) {
1701 route = XMLRouteFactory_2X (**niter, version);
1703 route = XMLRouteFactory (**niter, version);
1707 error << _("Session: cannot create Route from XML description.") << endmsg;
1711 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1713 new_routes.push_back (route);
1716 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1718 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1720 BootMessage (_("Finished adding tracks/busses"));
1725 boost::shared_ptr<Route>
1726 Session::XMLRouteFactory (const XMLNode& node, int version)
1728 boost::shared_ptr<Route> ret;
1730 if (node.name() != "Route") {
1734 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1736 DataType type = DataType::AUDIO;
1737 XMLProperty const * prop = node.property("default-type");
1740 type = DataType (prop->value());
1743 assert (type != DataType::NIL);
1747 boost::shared_ptr<Track> track;
1749 if (type == DataType::AUDIO) {
1750 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1752 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1755 if (track->init()) {
1759 if (track->set_state (node, version)) {
1763 BOOST_MARK_TRACK (track);
1767 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1768 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1770 if (r->init () == 0 && r->set_state (node, version) == 0) {
1771 BOOST_MARK_ROUTE (r);
1779 boost::shared_ptr<Route>
1780 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1782 boost::shared_ptr<Route> ret;
1784 if (node.name() != "Route") {
1788 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1790 ds_prop = node.property (X_("diskstream"));
1793 DataType type = DataType::AUDIO;
1794 XMLProperty const * prop = node.property("default-type");
1797 type = DataType (prop->value());
1800 assert (type != DataType::NIL);
1804 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1805 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1809 if (i == _diskstreams_2X.end()) {
1810 error << _("Could not find diskstream for route") << endmsg;
1811 return boost::shared_ptr<Route> ();
1814 boost::shared_ptr<Track> track;
1816 if (type == DataType::AUDIO) {
1817 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1819 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1822 if (track->init()) {
1826 if (track->set_state (node, version)) {
1830 track->set_diskstream (*i);
1832 BOOST_MARK_TRACK (track);
1836 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1837 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1839 if (r->init () == 0 && r->set_state (node, version) == 0) {
1840 BOOST_MARK_ROUTE (r);
1849 Session::load_regions (const XMLNode& node)
1852 XMLNodeConstIterator niter;
1853 boost::shared_ptr<Region> region;
1855 nlist = node.children();
1859 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1860 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1861 error << _("Session: cannot create Region from XML description.");
1862 XMLProperty const * name = (**niter).property("name");
1865 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1876 Session::load_compounds (const XMLNode& node)
1878 XMLNodeList calist = node.children();
1879 XMLNodeConstIterator caiter;
1880 XMLProperty const * caprop;
1882 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1883 XMLNode* ca = *caiter;
1887 if ((caprop = ca->property (X_("original"))) == 0) {
1890 orig_id = caprop->value();
1892 if ((caprop = ca->property (X_("copy"))) == 0) {
1895 copy_id = caprop->value();
1897 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1898 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1900 if (!orig || !copy) {
1901 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1907 RegionFactory::add_compound_association (orig, copy);
1914 Session::load_nested_sources (const XMLNode& node)
1917 XMLNodeConstIterator niter;
1919 nlist = node.children();
1921 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1922 if ((*niter)->name() == "Source") {
1924 /* it may already exist, so don't recreate it unnecessarily
1927 XMLProperty const * prop = (*niter)->property (X_("id"));
1929 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1933 ID source_id (prop->value());
1935 if (!source_by_id (source_id)) {
1938 SourceFactory::create (*this, **niter, true);
1940 catch (failed_constructor& err) {
1941 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1948 boost::shared_ptr<Region>
1949 Session::XMLRegionFactory (const XMLNode& node, bool full)
1951 XMLProperty const * type = node.property("type");
1955 const XMLNodeList& nlist = node.children();
1957 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1958 XMLNode *child = (*niter);
1959 if (child->name() == "NestedSource") {
1960 load_nested_sources (*child);
1964 if (!type || type->value() == "audio") {
1965 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1966 } else if (type->value() == "midi") {
1967 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1970 } catch (failed_constructor& err) {
1971 return boost::shared_ptr<Region> ();
1974 return boost::shared_ptr<Region> ();
1977 boost::shared_ptr<AudioRegion>
1978 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1980 XMLProperty const * prop;
1981 boost::shared_ptr<Source> source;
1982 boost::shared_ptr<AudioSource> as;
1984 SourceList master_sources;
1985 uint32_t nchans = 1;
1988 if (node.name() != X_("Region")) {
1989 return boost::shared_ptr<AudioRegion>();
1992 if ((prop = node.property (X_("channels"))) != 0) {
1993 nchans = atoi (prop->value().c_str());
1996 if ((prop = node.property ("name")) == 0) {
1997 cerr << "no name for this region\n";
2001 if ((prop = node.property (X_("source-0"))) == 0) {
2002 if ((prop = node.property ("source")) == 0) {
2003 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2004 return boost::shared_ptr<AudioRegion>();
2008 PBD::ID s_id (prop->value());
2010 if ((source = source_by_id (s_id)) == 0) {
2011 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2012 return boost::shared_ptr<AudioRegion>();
2015 as = boost::dynamic_pointer_cast<AudioSource>(source);
2017 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2018 return boost::shared_ptr<AudioRegion>();
2021 sources.push_back (as);
2023 /* pickup other channels */
2025 for (uint32_t n=1; n < nchans; ++n) {
2026 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2027 if ((prop = node.property (buf)) != 0) {
2029 PBD::ID id2 (prop->value());
2031 if ((source = source_by_id (id2)) == 0) {
2032 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2033 return boost::shared_ptr<AudioRegion>();
2036 as = boost::dynamic_pointer_cast<AudioSource>(source);
2038 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2039 return boost::shared_ptr<AudioRegion>();
2041 sources.push_back (as);
2045 for (uint32_t n = 0; n < nchans; ++n) {
2046 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2047 if ((prop = node.property (buf)) != 0) {
2049 PBD::ID id2 (prop->value());
2051 if ((source = source_by_id (id2)) == 0) {
2052 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2053 return boost::shared_ptr<AudioRegion>();
2056 as = boost::dynamic_pointer_cast<AudioSource>(source);
2058 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2059 return boost::shared_ptr<AudioRegion>();
2061 master_sources.push_back (as);
2066 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2068 /* a final detail: this is the one and only place that we know how long missing files are */
2070 if (region->whole_file()) {
2071 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2072 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2074 sfp->set_length (region->length());
2079 if (!master_sources.empty()) {
2080 if (master_sources.size() != nchans) {
2081 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2083 region->set_master_sources (master_sources);
2091 catch (failed_constructor& err) {
2092 return boost::shared_ptr<AudioRegion>();
2096 boost::shared_ptr<MidiRegion>
2097 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2099 XMLProperty const * prop;
2100 boost::shared_ptr<Source> source;
2101 boost::shared_ptr<MidiSource> ms;
2104 if (node.name() != X_("Region")) {
2105 return boost::shared_ptr<MidiRegion>();
2108 if ((prop = node.property ("name")) == 0) {
2109 cerr << "no name for this region\n";
2113 if ((prop = node.property (X_("source-0"))) == 0) {
2114 if ((prop = node.property ("source")) == 0) {
2115 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2116 return boost::shared_ptr<MidiRegion>();
2120 PBD::ID s_id (prop->value());
2122 if ((source = source_by_id (s_id)) == 0) {
2123 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2124 return boost::shared_ptr<MidiRegion>();
2127 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2129 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2130 return boost::shared_ptr<MidiRegion>();
2133 sources.push_back (ms);
2136 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2137 /* a final detail: this is the one and only place that we know how long missing files are */
2139 if (region->whole_file()) {
2140 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2141 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2143 sfp->set_length (region->length());
2151 catch (failed_constructor& err) {
2152 return boost::shared_ptr<MidiRegion>();
2157 Session::get_sources_as_xml ()
2160 XMLNode* node = new XMLNode (X_("Sources"));
2161 Glib::Threads::Mutex::Lock lm (source_lock);
2163 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2164 node->add_child_nocopy (i->second->get_state());
2171 Session::reset_write_sources (bool mark_write_complete, bool force)
2173 boost::shared_ptr<RouteList> rl = routes.reader();
2174 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2175 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2177 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2178 tr->reset_write_sources(mark_write_complete, force);
2179 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2185 Session::load_sources (const XMLNode& node)
2188 XMLNodeConstIterator niter;
2189 /* don't need this but it stops some
2190 * versions of gcc complaining about
2191 * discarded return values.
2193 boost::shared_ptr<Source> source;
2195 nlist = node.children();
2198 std::map<std::string, std::string> relocation;
2200 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2201 #ifdef PLATFORM_WINDOWS
2205 XMLNode srcnode (**niter);
2206 bool try_replace_abspath = true;
2210 #ifdef PLATFORM_WINDOWS
2211 // do not show "insert media" popups (files embedded from removable media).
2212 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2214 if ((source = XMLSourceFactory (srcnode)) == 0) {
2215 error << _("Session: cannot create Source from XML description.") << endmsg;
2217 #ifdef PLATFORM_WINDOWS
2218 SetErrorMode(old_mode);
2221 } catch (MissingSource& err) {
2222 #ifdef PLATFORM_WINDOWS
2223 SetErrorMode(old_mode);
2226 /* try previous abs path replacements first */
2227 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2228 std::string dir = Glib::path_get_dirname (err.path);
2229 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2230 if (rl != relocation.end ()) {
2231 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2232 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2233 srcnode.add_property ("origin", newpath);
2234 try_replace_abspath = false;
2241 _missing_file_replacement = "";
2243 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2244 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2245 PROGRAM_NAME) << endmsg;
2249 if (!no_questions_about_missing_files) {
2250 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2255 switch (user_choice) {
2257 /* user added a new search location
2258 * or selected a new absolute path,
2260 if (Glib::path_is_absolute (err.path)) {
2261 if (!_missing_file_replacement.empty ()) {
2262 /* replace origin, in XML */
2263 std::string newpath = Glib::build_filename (
2264 _missing_file_replacement, Glib::path_get_basename (err.path));
2265 srcnode.add_property ("origin", newpath);
2266 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2267 _missing_file_replacement = "";
2274 /* user asked to quit the entire session load */
2278 no_questions_about_missing_files = true;
2282 no_questions_about_missing_files = true;
2289 case DataType::AUDIO:
2290 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2293 case DataType::MIDI:
2294 /* The MIDI file is actually missing so
2295 * just create a new one in the same
2296 * location. Do not announce its
2300 if (!Glib::path_is_absolute (err.path)) {
2301 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2303 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2308 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2309 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2310 /* reset ID to match the missing one */
2311 source->set_id (**niter);
2312 /* Now we can announce it */
2313 SourceFactory::SourceCreated (source);
2324 boost::shared_ptr<Source>
2325 Session::XMLSourceFactory (const XMLNode& node)
2327 if (node.name() != "Source") {
2328 return boost::shared_ptr<Source>();
2332 /* note: do peak building in another thread when loading session state */
2333 return SourceFactory::create (*this, node, true);
2336 catch (failed_constructor& err) {
2337 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2338 return boost::shared_ptr<Source>();
2343 Session::save_template (string template_name, bool replace_existing)
2345 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2349 bool absolute_path = Glib::path_is_absolute (template_name);
2351 /* directory to put the template in */
2352 std::string template_dir_path;
2354 if (!absolute_path) {
2355 std::string user_template_dir(user_template_directory());
2357 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2358 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2359 user_template_dir, g_strerror (errno)) << endmsg;
2363 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2365 template_dir_path = template_name;
2368 if (!ARDOUR::Profile->get_trx()) {
2369 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2370 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2371 template_dir_path) << endmsg;
2375 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2376 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2377 template_dir_path, g_strerror (errno)) << endmsg;
2383 std::string template_file_path;
2385 if (ARDOUR::Profile->get_trx()) {
2386 template_file_path = template_name;
2388 if (absolute_path) {
2389 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2391 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2395 SessionSaveUnderway (); /* EMIT SIGNAL */
2400 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2401 tree.set_root (&get_template());
2404 if (!tree.write (template_file_path)) {
2405 error << _("template not saved") << endmsg;
2409 store_recent_templates (template_file_path);
2415 Session::refresh_disk_space ()
2417 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2419 Glib::Threads::Mutex::Lock lm (space_lock);
2421 /* get freespace on every FS that is part of the session path */
2423 _total_free_4k_blocks = 0;
2424 _total_free_4k_blocks_uncertain = false;
2426 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2427 #if defined(__NetBSD__)
2428 struct statvfs statfsbuf;
2430 statvfs (i->path.c_str(), &statfsbuf);
2432 struct statfs statfsbuf;
2434 statfs (i->path.c_str(), &statfsbuf);
2436 double const scale = statfsbuf.f_bsize / 4096.0;
2438 /* See if this filesystem is read-only */
2439 struct statvfs statvfsbuf;
2440 statvfs (i->path.c_str(), &statvfsbuf);
2442 /* f_bavail can be 0 if it is undefined for whatever
2443 filesystem we are looking at; Samba shares mounted
2444 via GVFS are an example of this.
2446 if (statfsbuf.f_bavail == 0) {
2447 /* block count unknown */
2449 i->blocks_unknown = true;
2450 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2451 /* read-only filesystem */
2453 i->blocks_unknown = false;
2455 /* read/write filesystem with known space */
2456 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2457 i->blocks_unknown = false;
2460 _total_free_4k_blocks += i->blocks;
2461 if (i->blocks_unknown) {
2462 _total_free_4k_blocks_uncertain = true;
2465 #elif defined PLATFORM_WINDOWS
2466 vector<string> scanned_volumes;
2467 vector<string>::iterator j;
2468 vector<space_and_path>::iterator i;
2469 DWORD nSectorsPerCluster, nBytesPerSector,
2470 nFreeClusters, nTotalClusters;
2474 _total_free_4k_blocks = 0;
2476 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2477 strncpy (disk_drive, (*i).path.c_str(), 3);
2481 volume_found = false;
2482 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2484 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2485 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2486 i->blocks = (uint32_t)(nFreeBytes / 4096);
2488 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2489 if (0 == j->compare(disk_drive)) {
2490 volume_found = true;
2495 if (!volume_found) {
2496 scanned_volumes.push_back(disk_drive);
2497 _total_free_4k_blocks += i->blocks;
2502 if (0 == _total_free_4k_blocks) {
2503 strncpy (disk_drive, path().c_str(), 3);
2506 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2508 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2509 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2510 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2517 Session::get_best_session_directory_for_new_audio ()
2519 vector<space_and_path>::iterator i;
2520 string result = _session_dir->root_path();
2522 /* handle common case without system calls */
2524 if (session_dirs.size() == 1) {
2528 /* OK, here's the algorithm we're following here:
2530 We want to select which directory to use for
2531 the next file source to be created. Ideally,
2532 we'd like to use a round-robin process so as to
2533 get maximum performance benefits from splitting
2534 the files across multiple disks.
2536 However, in situations without much diskspace, an
2537 RR approach may end up filling up a filesystem
2538 with new files while others still have space.
2539 Its therefore important to pay some attention to
2540 the freespace in the filesystem holding each
2541 directory as well. However, if we did that by
2542 itself, we'd keep creating new files in the file
2543 system with the most space until it was as full
2544 as all others, thus negating any performance
2545 benefits of this RAID-1 like approach.
2547 So, we use a user-configurable space threshold. If
2548 there are at least 2 filesystems with more than this
2549 much space available, we use RR selection between them.
2550 If not, then we pick the filesystem with the most space.
2552 This gets a good balance between the two
2556 refresh_disk_space ();
2558 int free_enough = 0;
2560 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2561 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2566 if (free_enough >= 2) {
2567 /* use RR selection process, ensuring that the one
2571 i = last_rr_session_dir;
2574 if (++i == session_dirs.end()) {
2575 i = session_dirs.begin();
2578 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2579 SessionDirectory sdir(i->path);
2580 if (sdir.create ()) {
2582 last_rr_session_dir = i;
2587 } while (i != last_rr_session_dir);
2591 /* pick FS with the most freespace (and that
2592 seems to actually work ...)
2595 vector<space_and_path> sorted;
2596 space_and_path_ascending_cmp cmp;
2598 sorted = session_dirs;
2599 sort (sorted.begin(), sorted.end(), cmp);
2601 for (i = sorted.begin(); i != sorted.end(); ++i) {
2602 SessionDirectory sdir(i->path);
2603 if (sdir.create ()) {
2605 last_rr_session_dir = i;
2615 Session::automation_dir () const
2617 return Glib::build_filename (_path, automation_dir_name);
2621 Session::analysis_dir () const
2623 return Glib::build_filename (_path, analysis_dir_name);
2627 Session::plugins_dir () const
2629 return Glib::build_filename (_path, plugins_dir_name);
2633 Session::externals_dir () const
2635 return Glib::build_filename (_path, externals_dir_name);
2639 Session::load_bundles (XMLNode const & node)
2641 XMLNodeList nlist = node.children();
2642 XMLNodeConstIterator niter;
2646 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2647 if ((*niter)->name() == "InputBundle") {
2648 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2649 } else if ((*niter)->name() == "OutputBundle") {
2650 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2652 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2661 Session::load_route_groups (const XMLNode& node, int version)
2663 XMLNodeList nlist = node.children();
2664 XMLNodeConstIterator niter;
2668 if (version >= 3000) {
2670 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2671 if ((*niter)->name() == "RouteGroup") {
2672 RouteGroup* rg = new RouteGroup (*this, "");
2673 add_route_group (rg);
2674 rg->set_state (**niter, version);
2678 } else if (version < 3000) {
2680 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2681 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2682 RouteGroup* rg = new RouteGroup (*this, "");
2683 add_route_group (rg);
2684 rg->set_state (**niter, version);
2693 state_file_filter (const string &str, void* /*arg*/)
2695 return (str.length() > strlen(statefile_suffix) &&
2696 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2700 remove_end(string state)
2702 string statename(state);
2704 string::size_type start,end;
2705 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2706 statename = statename.substr (start+1);
2709 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2710 end = statename.length();
2713 return string(statename.substr (0, end));
2717 Session::possible_states (string path)
2719 vector<string> states;
2720 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2722 transform(states.begin(), states.end(), states.begin(), remove_end);
2724 sort (states.begin(), states.end());
2730 Session::possible_states () const
2732 return possible_states(_path);
2736 Session::new_route_group (const std::string& name)
2738 RouteGroup* rg = NULL;
2740 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2741 if ((*i)->name () == name) {
2748 rg = new RouteGroup (*this, name);
2749 add_route_group (rg);
2755 Session::add_route_group (RouteGroup* g)
2757 _route_groups.push_back (g);
2758 route_group_added (g); /* EMIT SIGNAL */
2760 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2761 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2762 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2768 Session::remove_route_group (RouteGroup& rg)
2770 list<RouteGroup*>::iterator i;
2772 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2773 _route_groups.erase (i);
2776 route_group_removed (); /* EMIT SIGNAL */
2780 /** Set a new order for our route groups, without adding or removing any.
2781 * @param groups Route group list in the new order.
2784 Session::reorder_route_groups (list<RouteGroup*> groups)
2786 _route_groups = groups;
2788 route_groups_reordered (); /* EMIT SIGNAL */
2794 Session::route_group_by_name (string name)
2796 list<RouteGroup *>::iterator i;
2798 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2799 if ((*i)->name() == name) {
2807 Session::all_route_group() const
2809 return *_all_route_group;
2813 Session::add_commands (vector<Command*> const & cmds)
2815 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2821 Session::add_command (Command* const cmd)
2823 assert (_current_trans);
2824 DEBUG_UNDO_HISTORY (
2825 string_compose ("Current Undo Transaction %1, adding command: %2",
2826 _current_trans->name (),
2828 _current_trans->add_command (cmd);
2831 PBD::StatefulDiffCommand*
2832 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2834 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2840 Session::begin_reversible_command (const string& name)
2842 begin_reversible_command (g_quark_from_string (name.c_str ()));
2845 /** Begin a reversible command using a GQuark to identify it.
2846 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2847 * but there must be as many begin...()s as there are commit...()s.
2850 Session::begin_reversible_command (GQuark q)
2852 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2853 to hold all the commands that are committed. This keeps the order of
2854 commands correct in the history.
2857 if (_current_trans == 0) {
2858 DEBUG_UNDO_HISTORY (string_compose (
2859 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2861 /* start a new transaction */
2862 assert (_current_trans_quarks.empty ());
2863 _current_trans = new UndoTransaction();
2864 _current_trans->set_name (g_quark_to_string (q));
2866 DEBUG_UNDO_HISTORY (
2867 string_compose ("Begin Reversible Command, current transaction: %1",
2868 _current_trans->name ()));
2871 _current_trans_quarks.push_front (q);
2875 Session::abort_reversible_command ()
2877 if (_current_trans != 0) {
2878 DEBUG_UNDO_HISTORY (
2879 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2880 _current_trans->clear();
2881 delete _current_trans;
2883 _current_trans_quarks.clear();
2888 Session::commit_reversible_command (Command *cmd)
2890 assert (_current_trans);
2891 assert (!_current_trans_quarks.empty ());
2896 DEBUG_UNDO_HISTORY (
2897 string_compose ("Current Undo Transaction %1, adding command: %2",
2898 _current_trans->name (),
2900 _current_trans->add_command (cmd);
2903 DEBUG_UNDO_HISTORY (
2904 string_compose ("Commit Reversible Command, current transaction: %1",
2905 _current_trans->name ()));
2907 _current_trans_quarks.pop_front ();
2909 if (!_current_trans_quarks.empty ()) {
2910 DEBUG_UNDO_HISTORY (
2911 string_compose ("Commit Reversible Command, transaction is not "
2912 "top-level, current transaction: %1",
2913 _current_trans->name ()));
2914 /* the transaction we're committing is not the top-level one */
2918 if (_current_trans->empty()) {
2919 /* no commands were added to the transaction, so just get rid of it */
2920 DEBUG_UNDO_HISTORY (
2921 string_compose ("Commit Reversible Command, No commands were "
2922 "added to current transaction: %1",
2923 _current_trans->name ()));
2924 delete _current_trans;
2929 gettimeofday (&now, 0);
2930 _current_trans->set_timestamp (now);
2932 _history.add (_current_trans);
2937 accept_all_audio_files (const string& path, void* /*arg*/)
2939 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2943 if (!AudioFileSource::safe_audio_file_extension (path)) {
2951 accept_all_midi_files (const string& path, void* /*arg*/)
2953 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2957 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2958 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2959 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2963 accept_all_state_files (const string& path, void* /*arg*/)
2965 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2969 std::string const statefile_ext (statefile_suffix);
2970 if (path.length() >= statefile_ext.length()) {
2971 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2978 Session::find_all_sources (string path, set<string>& result)
2983 if (!tree.read (path)) {
2987 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2992 XMLNodeConstIterator niter;
2994 nlist = node->children();
2998 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3000 XMLProperty const * prop;
3002 if ((prop = (*niter)->property (X_("type"))) == 0) {
3006 DataType type (prop->value());
3008 if ((prop = (*niter)->property (X_("name"))) == 0) {
3012 if (Glib::path_is_absolute (prop->value())) {
3013 /* external file, ignore */
3021 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3022 result.insert (found_path);
3030 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3032 vector<string> state_files;
3034 string this_snapshot_path;
3040 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3041 ripped = ripped.substr (0, ripped.length() - 1);
3044 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3046 if (state_files.empty()) {
3051 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3052 this_snapshot_path += statefile_suffix;
3054 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3056 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3058 if (exclude_this_snapshot && *i == this_snapshot_path) {
3059 cerr << "\texcluded\n";
3064 if (find_all_sources (*i, result) < 0) {
3072 struct RegionCounter {
3073 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3074 AudioSourceList::iterator iter;
3075 boost::shared_ptr<Region> region;
3078 RegionCounter() : count (0) {}
3082 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3084 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3085 return r.get_value_or (1);
3089 Session::cleanup_regions ()
3091 bool removed = false;
3092 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3094 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3096 uint32_t used = playlists->region_use_count (i->second);
3098 if (used == 0 && !i->second->automatic ()) {
3099 boost::weak_ptr<Region> w = i->second;
3102 RegionFactory::map_remove (w);
3109 // re-check to remove parent references of compound regions
3110 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3111 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3115 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3116 if (0 == playlists->region_use_count (i->second)) {
3117 boost::weak_ptr<Region> w = i->second;
3119 RegionFactory::map_remove (w);
3126 /* dump the history list */
3133 Session::can_cleanup_peakfiles () const
3135 if (deletion_in_progress()) {
3138 if (!_writable || (_state_of_the_state & CannotSave)) {
3139 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3142 if (record_status() == Recording) {
3143 error << _("Cannot cleanup peak-files while recording") << endmsg;
3150 Session::cleanup_peakfiles ()
3152 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3157 assert (can_cleanup_peakfiles ());
3158 assert (!peaks_cleanup_in_progres());
3160 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3162 int timeout = 5000; // 5 seconds
3163 while (!SourceFactory::files_with_peaks.empty()) {
3164 Glib::usleep (1000);
3165 if (--timeout < 0) {
3166 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3167 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3172 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3173 boost::shared_ptr<AudioSource> as;
3174 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3175 as->close_peakfile();
3179 PBD::clear_directory (session_directory().peak_path());
3181 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3183 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3184 boost::shared_ptr<AudioSource> as;
3185 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3186 SourceFactory::setup_peakfile(as, true);
3193 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3195 pl->deep_sources (*all_sources);
3199 Session::cleanup_sources (CleanupReport& rep)
3201 // FIXME: needs adaptation to midi
3203 vector<boost::shared_ptr<Source> > dead_sources;
3206 vector<string> candidates;
3207 vector<string> unused;
3208 set<string> sources_used_by_all_snapshots;
3215 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3217 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3219 /* this is mostly for windows which doesn't allow file
3220 * renaming if the file is in use. But we don't special
3221 * case it because we need to know if this causes
3222 * problems, and the easiest way to notice that is to
3223 * keep it in place for all platforms.
3226 request_stop (false);
3228 _butler->wait_until_finished ();
3230 /* consider deleting all unused playlists */
3232 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3237 /* sync the "all regions" property of each playlist with its current state
3240 playlists->sync_all_regions_with_regions ();
3242 /* find all un-used sources */
3247 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3249 SourceMap::iterator tmp;
3254 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3258 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3259 dead_sources.push_back (i->second);
3260 i->second->drop_references ();
3266 /* build a list of all the possible audio directories for the session */
3268 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3269 SessionDirectory sdir ((*i).path);
3270 asp += sdir.sound_path();
3272 audio_path += asp.to_string();
3275 /* build a list of all the possible midi directories for the session */
3277 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3278 SessionDirectory sdir ((*i).path);
3279 msp += sdir.midi_path();
3281 midi_path += msp.to_string();
3283 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3284 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3286 /* add sources from all other snapshots as "used", but don't use this
3287 snapshot because the state file on disk still references sources we
3288 may have already dropped.
3291 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3293 /* Although the region factory has a list of all regions ever created
3294 * for this session, we're only interested in regions actually in
3295 * playlists right now. So merge all playlist regions lists together.
3297 * This will include the playlists used within compound regions.
3300 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3302 /* add our current source list
3305 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3306 boost::shared_ptr<FileSource> fs;
3307 SourceMap::iterator tmp = i;
3310 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3316 /* this is mostly for windows which doesn't allow file
3317 * renaming if the file is in use. But we do not special
3318 * case it because we need to know if this causes
3319 * problems, and the easiest way to notice that is to
3320 * keep it in place for all platforms.
3325 if (!fs->is_stub()) {
3327 /* Note that we're checking a list of all
3328 * sources across all snapshots with the list
3329 * of sources used by this snapshot.
3332 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3333 /* this source is in use by this snapshot */
3334 sources_used_by_all_snapshots.insert (fs->path());
3335 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3337 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3338 /* this source is NOT in use by this snapshot
3341 /* remove all related regions from RegionFactory master list
3344 RegionFactory::remove_regions_using_source (i->second);
3346 /* remove from our current source list
3347 * also. We may not remove it from
3348 * disk, because it may be used by
3349 * other snapshots, but it isn't used inside this
3350 * snapshot anymore, so we don't need a
3361 /* now check each candidate source to see if it exists in the list of
3362 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3365 cerr << "Candidates: " << candidates.size() << endl;
3366 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3368 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3373 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3375 tmppath1 = canonical_path (spath);
3376 tmppath2 = canonical_path ((*i));
3378 cerr << "\t => " << tmppath2 << endl;
3380 if (tmppath1 == tmppath2) {
3387 unused.push_back (spath);
3391 cerr << "Actually unused: " << unused.size() << endl;
3393 if (unused.empty()) {
3399 /* now try to move all unused files into the "dead" directory(ies) */
3401 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3406 /* don't move the file across filesystems, just
3407 stick it in the `dead_dir_name' directory
3408 on whichever filesystem it was already on.
3411 if ((*x).find ("/sounds/") != string::npos) {
3413 /* old school, go up 1 level */
3415 newpath = Glib::path_get_dirname (*x); // "sounds"
3416 newpath = Glib::path_get_dirname (newpath); // "session-name"
3420 /* new school, go up 4 levels */
3422 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3423 newpath = Glib::path_get_dirname (newpath); // "session-name"
3424 newpath = Glib::path_get_dirname (newpath); // "interchange"
3425 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3428 newpath = Glib::build_filename (newpath, dead_dir_name);
3430 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3431 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3435 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3437 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3439 /* the new path already exists, try versioning */
3441 char buf[PATH_MAX+1];
3445 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3448 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3449 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3453 if (version == 999) {
3454 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3458 newpath = newpath_v;
3463 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3464 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3465 newpath, g_strerror (errno)) << endmsg;
3469 /* see if there an easy to find peakfile for this file, and remove it.
3472 string base = Glib::path_get_basename (*x);
3473 base += "%A"; /* this is what we add for the channel suffix of all native files,
3474 or for the first channel of embedded files. it will miss
3475 some peakfiles for other channels
3477 string peakpath = construct_peak_filepath (base);
3479 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3480 if (::g_unlink (peakpath.c_str ()) != 0) {
3481 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3482 g_strerror (errno)) << endmsg;
3483 /* try to back out */
3484 ::g_rename (newpath.c_str (), _path.c_str ());
3489 rep.paths.push_back (*x);
3490 rep.space += statbuf.st_size;
3493 /* dump the history list */
3497 /* save state so we don't end up a session file
3498 referring to non-existent sources.
3505 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3511 Session::cleanup_trash_sources (CleanupReport& rep)
3513 // FIXME: needs adaptation for MIDI
3515 vector<space_and_path>::iterator i;
3521 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3523 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3525 clear_directory (dead_dir, &rep.space, &rep.paths);
3532 Session::set_dirty ()
3534 /* return early if there's nothing to do */
3539 /* never mark session dirty during loading */
3540 if (_state_of_the_state & Loading) {
3544 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3545 DirtyChanged(); /* EMIT SIGNAL */
3549 Session::set_clean ()
3551 bool was_dirty = dirty();
3553 _state_of_the_state = Clean;
3556 DirtyChanged(); /* EMIT SIGNAL */
3561 Session::set_deletion_in_progress ()
3563 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3567 Session::clear_deletion_in_progress ()
3569 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3573 Session::add_controllable (boost::shared_ptr<Controllable> c)
3575 /* this adds a controllable to the list managed by the Session.
3576 this is a subset of those managed by the Controllable class
3577 itself, and represents the only ones whose state will be saved
3578 as part of the session.
3581 Glib::Threads::Mutex::Lock lm (controllables_lock);
3582 controllables.insert (c);
3585 struct null_deleter { void operator()(void const *) const {} };
3588 Session::remove_controllable (Controllable* c)
3590 if (_state_of_the_state & Deletion) {
3594 Glib::Threads::Mutex::Lock lm (controllables_lock);
3596 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3598 if (x != controllables.end()) {
3599 controllables.erase (x);
3603 boost::shared_ptr<Controllable>
3604 Session::controllable_by_id (const PBD::ID& id)
3606 Glib::Threads::Mutex::Lock lm (controllables_lock);
3608 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3609 if ((*i)->id() == id) {
3614 return boost::shared_ptr<Controllable>();
3617 boost::shared_ptr<Controllable>
3618 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3620 boost::shared_ptr<Controllable> c;
3621 boost::shared_ptr<Stripable> s;
3622 boost::shared_ptr<Route> r;
3624 switch (desc.top_level_type()) {
3625 case ControllableDescriptor::NamedRoute:
3627 std::string str = desc.top_level_name();
3629 if (str == "Master" || str == "master") {
3631 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3633 } else if (str == "auditioner") {
3636 s = route_by_name (desc.top_level_name());
3642 case ControllableDescriptor::PresentationOrderRoute:
3643 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3646 case ControllableDescriptor::PresentationOrderTrack:
3647 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3650 case ControllableDescriptor::PresentationOrderBus:
3651 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3654 case ControllableDescriptor::PresentationOrderVCA:
3655 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3658 case ControllableDescriptor::SelectionCount:
3659 s = route_by_selected_count (desc.selection_id());
3667 r = boost::dynamic_pointer_cast<Route> (s);
3669 switch (desc.subtype()) {
3670 case ControllableDescriptor::Gain:
3671 c = s->gain_control ();
3674 case ControllableDescriptor::Trim:
3675 c = s->trim_control ();
3678 case ControllableDescriptor::Solo:
3679 c = s->solo_control();
3682 case ControllableDescriptor::Mute:
3683 c = s->mute_control();
3686 case ControllableDescriptor::Recenable:
3687 c = s->rec_enable_control ();
3690 case ControllableDescriptor::PanDirection:
3691 c = s->pan_azimuth_control();
3694 case ControllableDescriptor::PanWidth:
3695 c = s->pan_width_control();
3698 case ControllableDescriptor::PanElevation:
3699 c = s->pan_elevation_control();
3702 case ControllableDescriptor::Balance:
3703 /* XXX simple pan control */
3706 case ControllableDescriptor::PluginParameter:
3708 uint32_t plugin = desc.target (0);
3709 uint32_t parameter_index = desc.target (1);
3711 /* revert to zero based counting */
3717 if (parameter_index > 0) {
3725 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3728 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3729 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3734 case ControllableDescriptor::SendGain: {
3735 uint32_t send = desc.target (0);
3742 c = r->send_level_controllable (send);
3747 /* relax and return a null pointer */
3755 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3758 Stateful::add_instant_xml (node, _path);
3761 if (write_to_config) {
3762 Config->add_instant_xml (node);
3767 Session::instant_xml (const string& node_name)
3769 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3770 if (get_disable_all_loaded_plugins ()) {
3774 return Stateful::instant_xml (node_name, _path);
3778 Session::save_history (string snapshot_name)
3786 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3787 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3791 if (snapshot_name.empty()) {
3792 snapshot_name = _current_snapshot_name;
3795 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3796 const string backup_filename = history_filename + backup_suffix;
3797 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3798 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3800 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3801 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3802 error << _("could not backup old history file, current history not saved") << endmsg;
3807 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3809 if (!tree.write (xml_path))
3811 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3813 if (g_remove (xml_path.c_str()) != 0) {
3814 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3815 xml_path, g_strerror (errno)) << endmsg;
3817 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3818 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3819 backup_path, g_strerror (errno)) << endmsg;
3829 Session::restore_history (string snapshot_name)
3833 if (snapshot_name.empty()) {
3834 snapshot_name = _current_snapshot_name;
3837 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3838 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3840 info << "Loading history from " << xml_path << endmsg;
3842 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3843 info << string_compose (_("%1: no history file \"%2\" for this session."),
3844 _name, xml_path) << endmsg;
3848 if (!tree.read (xml_path)) {
3849 error << string_compose (_("Could not understand session history file \"%1\""),
3850 xml_path) << endmsg;
3857 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3860 UndoTransaction* ut = new UndoTransaction ();
3863 ut->set_name(t->property("name")->value());
3864 stringstream ss(t->property("tv-sec")->value());
3866 ss.str(t->property("tv-usec")->value());
3868 ut->set_timestamp(tv);
3870 for (XMLNodeConstIterator child_it = t->children().begin();
3871 child_it != t->children().end(); child_it++)
3873 XMLNode *n = *child_it;
3876 if (n->name() == "MementoCommand" ||
3877 n->name() == "MementoUndoCommand" ||
3878 n->name() == "MementoRedoCommand") {
3880 if ((c = memento_command_factory(n))) {
3884 } else if (n->name() == "NoteDiffCommand") {
3885 PBD::ID id (n->property("midi-source")->value());
3886 boost::shared_ptr<MidiSource> midi_source =
3887 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3889 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3891 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3894 } else if (n->name() == "SysExDiffCommand") {
3896 PBD::ID id (n->property("midi-source")->value());
3897 boost::shared_ptr<MidiSource> midi_source =
3898 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3900 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3902 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3905 } else if (n->name() == "PatchChangeDiffCommand") {
3907 PBD::ID id (n->property("midi-source")->value());
3908 boost::shared_ptr<MidiSource> midi_source =
3909 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3911 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3913 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3916 } else if (n->name() == "StatefulDiffCommand") {
3917 if ((c = stateful_diff_command_factory (n))) {
3918 ut->add_command (c);
3921 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3932 Session::config_changed (std::string p, bool ours)
3938 if (p == "seamless-loop") {
3940 } else if (p == "rf-speed") {
3942 } else if (p == "auto-loop") {
3944 } else if (p == "session-monitoring") {
3946 } else if (p == "auto-input") {
3948 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3949 /* auto-input only makes a difference if we're rolling */
3950 set_track_monitor_input_status (!config.get_auto_input());
3953 } else if (p == "punch-in") {
3957 if ((location = _locations->auto_punch_location()) != 0) {
3959 if (config.get_punch_in ()) {
3960 replace_event (SessionEvent::PunchIn, location->start());
3962 remove_event (location->start(), SessionEvent::PunchIn);
3966 } else if (p == "punch-out") {
3970 if ((location = _locations->auto_punch_location()) != 0) {
3972 if (config.get_punch_out()) {
3973 replace_event (SessionEvent::PunchOut, location->end());
3975 clear_events (SessionEvent::PunchOut);
3979 } else if (p == "edit-mode") {
3981 Glib::Threads::Mutex::Lock lm (playlists->lock);
3983 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3984 (*i)->set_edit_mode (Config->get_edit_mode ());
3987 } else if (p == "use-video-sync") {
3989 waiting_for_sync_offset = config.get_use_video_sync();
3991 } else if (p == "mmc-control") {
3993 //poke_midi_thread ();
3995 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3997 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3999 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4001 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4003 } else if (p == "midi-control") {
4005 //poke_midi_thread ();
4007 } else if (p == "raid-path") {
4009 setup_raid_path (config.get_raid_path());
4011 } else if (p == "timecode-format") {
4015 } else if (p == "video-pullup") {
4019 } else if (p == "seamless-loop") {
4021 if (play_loop && transport_rolling()) {
4022 // to reset diskstreams etc
4023 request_play_loop (true);
4026 } else if (p == "rf-speed") {
4028 cumulative_rf_motion = 0;
4031 } else if (p == "click-sound") {
4033 setup_click_sounds (1);
4035 } else if (p == "click-emphasis-sound") {
4037 setup_click_sounds (-1);
4039 } else if (p == "clicking") {
4041 if (Config->get_clicking()) {
4042 if (_click_io && click_data) { // don't require emphasis data
4049 } else if (p == "click-record-only") {
4051 _click_rec_only = Config->get_click_record_only();
4053 } else if (p == "click-gain") {
4056 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4059 } else if (p == "send-mtc") {
4061 if (Config->get_send_mtc ()) {
4062 /* mark us ready to send */
4063 next_quarter_frame_to_send = 0;
4066 } else if (p == "send-mmc") {
4068 _mmc->enable_send (Config->get_send_mmc ());
4070 } else if (p == "jack-time-master") {
4072 engine().reset_timebase ();
4074 } else if (p == "native-file-header-format") {
4076 if (!first_file_header_format_reset) {
4077 reset_native_file_format ();
4080 first_file_header_format_reset = false;
4082 } else if (p == "native-file-data-format") {
4084 if (!first_file_data_format_reset) {
4085 reset_native_file_format ();
4088 first_file_data_format_reset = false;
4090 } else if (p == "external-sync") {
4091 if (!config.get_external_sync()) {
4092 drop_sync_source ();
4094 switch_to_sync_source (Config->get_sync_source());
4096 } else if (p == "denormal-model") {
4098 } else if (p == "history-depth") {
4099 set_history_depth (Config->get_history_depth());
4100 } else if (p == "remote-model") {
4101 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4104 } else if (p == "initial-program-change") {
4106 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4109 buf[0] = MIDI::program; // channel zero by default
4110 buf[1] = (Config->get_initial_program_change() & 0x7f);
4112 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4114 } else if (p == "solo-mute-override") {
4115 // catch_up_on_solo_mute_override ();
4116 } else if (p == "listen-position" || p == "pfl-position") {
4117 listen_position_changed ();
4118 } else if (p == "solo-control-is-listen-control") {
4119 solo_control_mode_changed ();
4120 } else if (p == "solo-mute-gain") {
4121 _solo_cut_control->Changed (true, Controllable::NoGroup);
4122 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4123 last_timecode_valid = false;
4124 } else if (p == "playback-buffer-seconds") {
4125 AudioSource::allocate_working_buffers (frame_rate());
4126 } else if (p == "ltc-source-port") {
4127 reconnect_ltc_input ();
4128 } else if (p == "ltc-sink-port") {
4129 reconnect_ltc_output ();
4130 } else if (p == "timecode-generator-offset") {
4131 ltc_tx_parse_offset();
4132 } else if (p == "auto-return-target-list") {
4133 follow_playhead_priority ();
4140 Session::set_history_depth (uint32_t d)
4142 _history.set_depth (d);
4146 Session::load_diskstreams_2X (XMLNode const & node, int)
4149 XMLNodeConstIterator citer;
4151 clist = node.children();
4153 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4156 /* diskstreams added automatically by DiskstreamCreated handler */
4157 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4158 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4159 _diskstreams_2X.push_back (dsp);
4161 error << _("Session: unknown diskstream type in XML") << endmsg;
4165 catch (failed_constructor& err) {
4166 error << _("Session: could not load diskstream via XML state") << endmsg;
4174 /** Connect things to the MMC object */
4176 Session::setup_midi_machine_control ()
4178 _mmc = new MIDI::MachineControl;
4180 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4181 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4183 if (!async_out || !async_out) {
4187 /* XXXX argh, passing raw pointers back into libmidi++ */
4189 MIDI::Port* mmc_in = async_in.get();
4190 MIDI::Port* mmc_out = async_out.get();
4192 _mmc->set_ports (mmc_in, mmc_out);
4194 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4195 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4196 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4197 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4198 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4199 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4200 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4201 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4202 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4203 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4204 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4205 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4206 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4208 /* also handle MIDI SPP because its so common */
4210 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4211 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4212 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4215 boost::shared_ptr<Controllable>
4216 Session::solo_cut_control() const
4218 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4219 controls in Ardour that currently get presented to the user in the GUI that require
4220 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4222 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4223 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4227 return _solo_cut_control;
4231 Session::save_snapshot_name (const std::string & n)
4233 /* assure Stateful::_instant_xml is loaded
4234 * add_instant_xml() only adds to existing data and defaults
4235 * to use an empty Tree otherwise
4237 instant_xml ("LastUsedSnapshot");
4239 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4240 last_used_snapshot->add_property ("name", string(n));
4241 add_instant_xml (*last_used_snapshot, false);
4245 Session::set_snapshot_name (const std::string & n)
4247 _current_snapshot_name = n;
4248 save_snapshot_name (n);
4252 Session::rename (const std::string& new_name)
4254 string legal_name = legalize_for_path (new_name);
4260 string const old_sources_root = _session_dir->sources_root();
4262 if (!_writable || (_state_of_the_state & CannotSave)) {
4263 error << _("Cannot rename read-only session.") << endmsg;
4264 return 0; // don't show "messed up" warning
4266 if (record_status() == Recording) {
4267 error << _("Cannot rename session while recording") << endmsg;
4268 return 0; // don't show "messed up" warning
4271 StateProtector stp (this);
4276 * interchange subdirectory
4280 * Backup files are left unchanged and not renamed.
4283 /* Windows requires that we close all files before attempting the
4284 * rename. This works on other platforms, but isn't necessary there.
4285 * Leave it in place for all platforms though, since it may help
4286 * catch issues that could arise if the way Source files work ever
4287 * change (since most developers are not using Windows).
4290 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4291 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4297 /* pass one: not 100% safe check that the new directory names don't
4301 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4305 /* this is a stupid hack because Glib::path_get_dirname() is
4306 * lexical-only, and so passing it /a/b/c/ gives a different
4307 * result than passing it /a/b/c ...
4310 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4311 oldstr = oldstr.substr (0, oldstr.length() - 1);
4314 string base = Glib::path_get_dirname (oldstr);
4316 newstr = Glib::build_filename (base, legal_name);
4318 cerr << "Looking for " << newstr << endl;
4320 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4321 cerr << " exists\n";
4330 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4336 /* this is a stupid hack because Glib::path_get_dirname() is
4337 * lexical-only, and so passing it /a/b/c/ gives a different
4338 * result than passing it /a/b/c ...
4341 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4342 oldstr = oldstr.substr (0, oldstr.length() - 1);
4345 string base = Glib::path_get_dirname (oldstr);
4346 newstr = Glib::build_filename (base, legal_name);
4348 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4350 cerr << "Rename " << oldstr << " => " << newstr << endl;
4351 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4352 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4353 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4357 /* Reset path in "session dirs" */
4362 /* reset primary SessionDirectory object */
4365 (*_session_dir) = newstr;
4370 /* now rename directory below session_dir/interchange */
4372 string old_interchange_dir;
4373 string new_interchange_dir;
4375 /* use newstr here because we renamed the path
4376 * (folder/directory) that used to be oldstr to newstr above
4379 v.push_back (newstr);
4380 v.push_back (interchange_dir_name);
4381 v.push_back (Glib::path_get_basename (oldstr));
4383 old_interchange_dir = Glib::build_filename (v);
4386 v.push_back (newstr);
4387 v.push_back (interchange_dir_name);
4388 v.push_back (legal_name);
4390 new_interchange_dir = Glib::build_filename (v);
4392 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4394 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4395 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4396 old_interchange_dir, new_interchange_dir,
4399 error << string_compose (_("renaming %s as %2 failed (%3)"),
4400 old_interchange_dir, new_interchange_dir,
4409 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4410 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4412 cerr << "Rename " << oldstr << " => " << newstr << endl;
4414 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4415 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4416 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4422 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4424 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4425 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4427 cerr << "Rename " << oldstr << " => " << newstr << endl;
4429 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4430 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4431 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4436 /* remove old name from recent sessions */
4437 remove_recent_sessions (_path);
4440 /* update file source paths */
4442 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4443 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4445 string p = fs->path ();
4446 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4448 SourceFactory::setup_peakfile(i->second, true);
4452 set_snapshot_name (new_name);
4457 /* save state again to get everything just right */
4459 save_state (_current_snapshot_name);
4461 /* add to recent sessions */
4463 store_recent_sessions (new_name, _path);
4469 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4471 bool found_sr = false;
4472 bool found_data_format = false;
4473 program_version = "";
4475 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4479 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4483 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4486 xmlFreeParserCtxt(ctxt);
4490 xmlNodePtr node = xmlDocGetRootElement(doc);
4493 xmlFreeParserCtxt(ctxt);
4501 for (attr = node->properties; attr; attr = attr->next) {
4502 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4503 sample_rate = atoi ((char*)attr->children->content);
4508 node = node->children;
4509 while (node != NULL) {
4510 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4511 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4513 program_version = string ((const char*)val);
4514 size_t sep = program_version.find_first_of("-");
4515 if (sep != string::npos) {
4516 program_version = program_version.substr (0, sep);
4521 if (strcmp((const char*) node->name, "Config")) {
4525 for (node = node->children; node; node = node->next) {
4526 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4527 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4529 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4531 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4533 found_data_format = true;
4543 xmlFreeParserCtxt(ctxt);
4546 return !(found_sr && found_data_format); // zero if they are both found
4550 Session::get_snapshot_from_instant (const std::string& session_dir)
4552 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4554 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4559 if (!tree.read (instant_xml_path)) {
4563 XMLProperty const * prop;
4564 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4565 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4566 return prop->value();
4572 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4573 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4576 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4580 SourcePathMap source_path_map;
4582 boost::shared_ptr<AudioFileSource> afs;
4587 Glib::Threads::Mutex::Lock lm (source_lock);
4589 cerr << " total sources = " << sources.size();
4591 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4592 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4598 if (fs->within_session()) {
4602 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4603 source_path_map[fs->path()].push_back (fs);
4605 SeveralFileSources v;
4607 source_path_map.insert (make_pair (fs->path(), v));
4613 cerr << " fsources = " << total << endl;
4615 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4617 /* tell caller where we are */
4619 string old_path = i->first;
4621 callback (n, total, old_path);
4623 cerr << old_path << endl;
4627 switch (i->second.front()->type()) {
4628 case DataType::AUDIO:
4629 new_path = new_audio_source_path_for_embedded (old_path);
4632 case DataType::MIDI:
4633 /* XXX not implemented yet */
4637 if (new_path.empty()) {
4641 cerr << "Move " << old_path << " => " << new_path << endl;
4643 if (!copy_file (old_path, new_path)) {
4644 cerr << "failed !\n";
4648 /* make sure we stop looking in the external
4649 dir/folder. Remember, this is an all-or-nothing
4650 operations, it doesn't merge just some files.
4652 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4654 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4655 (*f)->set_path (new_path);
4660 save_state ("", false, false);
4666 bool accept_all_files (string const &, void *)
4672 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4674 /* It would be good if this did something useful vis-a-vis save-as, but the arguments doesn't provide the correct information right now to do this.
4679 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4681 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4683 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4685 v.push_back (new_session_folder); /* full path */
4686 v.push_back (interchange_dir_name);
4687 v.push_back (new_session_path); /* just one directory/folder */
4688 v.push_back (typedir);
4689 v.push_back (Glib::path_get_basename (old_path));
4691 return Glib::build_filename (v);
4695 Session::save_as (SaveAs& saveas)
4697 vector<string> files;
4698 string current_folder = Glib::path_get_dirname (_path);
4699 string new_folder = legalize_for_path (saveas.new_name);
4700 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4701 int64_t total_bytes = 0;
4705 int32_t internal_file_cnt = 0;
4707 vector<string> do_not_copy_extensions;
4708 do_not_copy_extensions.push_back (statefile_suffix);
4709 do_not_copy_extensions.push_back (pending_suffix);
4710 do_not_copy_extensions.push_back (backup_suffix);
4711 do_not_copy_extensions.push_back (temp_suffix);
4712 do_not_copy_extensions.push_back (history_suffix);
4714 /* get total size */
4716 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4718 /* need to clear this because
4719 * find_files_matching_filter() is cumulative
4724 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4726 all += files.size();
4728 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4730 g_stat ((*i).c_str(), &gsb);
4731 total_bytes += gsb.st_size;
4735 /* save old values so we can switch back if we are not switching to the new session */
4737 string old_path = _path;
4738 string old_name = _name;
4739 string old_snapshot = _current_snapshot_name;
4740 string old_sd = _session_dir->root_path();
4741 vector<string> old_search_path[DataType::num_types];
4742 string old_config_search_path[DataType::num_types];
4744 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4745 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4746 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4747 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4749 /* switch session directory */
4751 (*_session_dir) = to_dir;
4753 /* create new tree */
4755 if (!_session_dir->create()) {
4756 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4761 /* copy all relevant files. Find each location in session_dirs,
4762 * and copy files from there to target.
4765 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4767 /* need to clear this because
4768 * find_files_matching_filter() is cumulative
4773 const size_t prefix_len = (*sd).path.size();
4775 /* Work just on the files within this session dir */
4777 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4779 /* add dir separator to protect against collisions with
4780 * track names (e.g. track named "audiofiles" or
4784 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4785 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4786 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4788 /* copy all the files. Handling is different for media files
4789 than others because of the *silly* subtree we have below the interchange
4790 folder. That really was a bad idea, but I'm not fixing it as part of
4791 implementing ::save_as().
4794 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4796 std::string from = *i;
4799 string filename = Glib::path_get_basename (from);
4800 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4801 if (filename == ".DS_STORE") {
4806 if (from.find (audiofile_dir_string) != string::npos) {
4808 /* audio file: only copy if asked */
4810 if (saveas.include_media && saveas.copy_media) {
4812 string to = make_new_media_path (*i, to_dir, new_folder);
4814 info << "media file copying from " << from << " to " << to << endmsg;
4816 if (!copy_file (from, to)) {
4817 throw Glib::FileError (Glib::FileError::IO_ERROR,
4818 string_compose(_("\ncopying \"%1\" failed !"), from));
4822 /* we found media files inside the session folder */
4824 internal_file_cnt++;
4826 } else if (from.find (midifile_dir_string) != string::npos) {
4828 /* midi file: always copy unless
4829 * creating an empty new session
4832 if (saveas.include_media) {
4834 string to = make_new_media_path (*i, to_dir, new_folder);
4836 info << "media file copying from " << from << " to " << to << endmsg;
4838 if (!copy_file (from, to)) {
4839 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4843 /* we found media files inside the session folder */
4845 internal_file_cnt++;
4847 } else if (from.find (analysis_dir_string) != string::npos) {
4849 /* make sure analysis dir exists in
4850 * new session folder, but we're not
4851 * copying analysis files here, see
4855 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4860 /* normal non-media file. Don't copy state, history, etc.
4863 bool do_copy = true;
4865 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4866 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4867 /* end of filename matches extension, do not copy file */
4873 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4874 /* don't copy peakfiles if
4875 * we're not copying media
4881 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4883 info << "attempting to make directory/folder " << to << endmsg;
4885 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4886 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4889 info << "attempting to copy " << from << " to " << to << endmsg;
4891 if (!copy_file (from, to)) {
4892 throw Glib::FileError (Glib::FileError::IO_ERROR,
4893 string_compose(_("\ncopying \"%1\" failed !"), from));
4898 /* measure file size even if we're not going to copy so that our Progress
4899 signals are correct, since we included these do-not-copy files
4900 in the computation of the total size and file count.
4904 g_stat (from.c_str(), &gsb);
4905 copied += gsb.st_size;
4908 double fraction = (double) copied / total_bytes;
4910 bool keep_going = true;
4912 if (saveas.copy_media) {
4914 /* no need or expectation of this if
4915 * media is not being copied, because
4916 * it will be fast(ish).
4919 /* tell someone "X percent, file M of N"; M is one-based */
4921 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4929 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4935 /* copy optional folders, if any */
4937 string old = plugins_dir ();
4938 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4939 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4940 copy_files (old, newdir);
4943 old = externals_dir ();
4944 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4945 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4946 copy_files (old, newdir);
4949 old = automation_dir ();
4950 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4951 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4952 copy_files (old, newdir);
4955 if (saveas.include_media) {
4957 if (saveas.copy_media) {
4958 #ifndef PLATFORM_WINDOWS
4959 /* There are problems with analysis files on
4960 * Windows, because they used a colon in their
4961 * names as late as 4.0. Colons are not legal
4962 * under Windows even if NTFS allows them.
4964 * This is a tricky problem to solve so for
4965 * just don't copy these files. They will be
4966 * regenerated as-needed anyway, subject to the
4967 * existing issue that the filenames will be
4968 * rejected by Windows, which is a separate
4969 * problem (though related).
4972 /* only needed if we are copying media, since the
4973 * analysis data refers to media data
4976 old = analysis_dir ();
4977 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4978 string newdir = Glib::build_filename (to_dir, "analysis");
4979 copy_files (old, newdir);
4981 #endif /* PLATFORM_WINDOWS */
4986 set_snapshot_name (saveas.new_name);
4987 _name = saveas.new_name;
4989 if (saveas.include_media && !saveas.copy_media) {
4991 /* reset search paths of the new session (which we're pretending to be right now) to
4992 include the original session search path, so we can still find all audio.
4995 if (internal_file_cnt) {
4996 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4997 ensure_search_path_includes (*s, DataType::AUDIO);
4998 cerr << "be sure to include " << *s << " for audio" << endl;
5001 /* we do not do this for MIDI because we copy
5002 all MIDI files if saveas.include_media is
5008 bool was_dirty = dirty ();
5010 save_default_options ();
5012 if (saveas.copy_media && saveas.copy_external) {
5013 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5014 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5018 saveas.final_session_folder_name = _path;
5020 store_recent_sessions (_name, _path);
5022 if (!saveas.switch_to) {
5024 /* save the new state */
5026 save_state ("", false, false, !saveas.include_media);
5028 /* switch back to the way things were */
5032 set_snapshot_name (old_snapshot);
5034 (*_session_dir) = old_sd;
5040 if (internal_file_cnt) {
5041 /* reset these to their original values */
5042 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5043 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5048 /* prune session dirs, and update disk space statistics
5053 session_dirs.clear ();
5054 session_dirs.push_back (sp);
5055 refresh_disk_space ();
5057 /* ensure that all existing tracks reset their current capture source paths
5059 reset_write_sources (true, true);
5061 /* creating new write sources marks the session as
5062 dirty. If the new session is empty, then
5063 save_state() thinks we're saving a template and will
5064 not mark the session as clean. So do that here,
5065 before we save state.
5068 if (!saveas.include_media) {
5069 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5072 save_state ("", false, false, !saveas.include_media);
5074 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5075 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5078 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5079 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5085 if (fs->within_session()) {
5086 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5087 fs->set_path (newpath);
5092 } catch (Glib::FileError& e) {
5094 saveas.failure_message = e.what();
5096 /* recursively remove all the directories */
5098 remove_directory (to_dir);
5106 saveas.failure_message = _("unknown reason");
5108 /* recursively remove all the directories */
5110 remove_directory (to_dir);
5120 static void set_progress (Progress* p, size_t n, size_t t)
5122 p->set_progress (float (n) / float(t));
5126 Session::archive_session (const std::string& dest,
5127 const std::string& name,
5128 ArchiveEncode compress_audio,
5129 bool only_used_sources,
5132 if (dest.empty () || name.empty ()) {
5136 /* save current values */
5137 bool was_dirty = dirty ();
5138 string old_path = _path;
5139 string old_name = _name;
5140 string old_snapshot = _current_snapshot_name;
5141 string old_sd = _session_dir->root_path();
5142 string old_config_search_path[DataType::num_types];
5143 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5144 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5146 /* ensure that session-path is included in search-path */
5148 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5149 if ((*sd).path == old_path) {
5157 /* create temporary dir to save session to */
5158 #ifdef PLATFORM_WINDOWS
5159 char tmp[256] = "C:\\TEMP\\";
5160 GetTempPath (sizeof (tmp), tmp);
5162 char const* tmp = getenv("TMPDIR");
5167 if ((strlen (tmp) + 21) > 1024) {
5172 strcpy (tmptpl, tmp);
5173 strcat (tmptpl, "ardourarchive-XXXXXX");
5174 char* tmpdir = g_mkdtemp (tmptpl);
5180 std::string to_dir = std::string (tmpdir);
5182 /* switch session directory temporarily */
5183 (*_session_dir) = to_dir;
5185 if (!_session_dir->create()) {
5186 (*_session_dir) = old_sd;
5187 remove_directory (to_dir);
5191 /* prepare archive */
5192 string archive = Glib::build_filename (dest, name + ".tar.xz");
5194 PBD::ScopedConnectionList progress_connection;
5195 PBD::FileArchive ar (archive);
5197 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5200 /* collect files to archive */
5201 std::map<string,string> filemap;
5203 vector<string> do_not_copy_extensions;
5204 do_not_copy_extensions.push_back (statefile_suffix);
5205 do_not_copy_extensions.push_back (pending_suffix);
5206 do_not_copy_extensions.push_back (backup_suffix);
5207 do_not_copy_extensions.push_back (temp_suffix);
5208 do_not_copy_extensions.push_back (history_suffix);
5210 vector<string> blacklist_dirs;
5211 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5212 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5213 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5214 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5215 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5216 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5218 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5219 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5221 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5222 if (only_used_sources) {
5223 playlists->sync_all_regions_with_regions ();
5224 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5227 // collect audio sources for this session, calc total size for encoding
5228 // add option to only include *used* sources (see Session::cleanup_sources)
5229 size_t total_size = 0;
5231 Glib::Threads::Mutex::Lock lm (source_lock);
5232 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5233 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5234 if (!afs || afs->readable_length () == 0) {
5238 if (only_used_sources) {
5242 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5247 std::string from = afs->path();
5249 if (compress_audio != NO_ENCODE) {
5250 total_size += afs->readable_length ();
5252 if (afs->within_session()) {
5253 filemap[from] = make_new_media_path (from, name, name);
5255 filemap[from] = make_new_media_path (from, name, name);
5256 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5263 if (compress_audio != NO_ENCODE) {
5265 progress->set_progress (2); // set to "encoding"
5266 progress->set_progress (0);
5269 Glib::Threads::Mutex::Lock lm (source_lock);
5270 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5271 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5272 if (!afs || afs->readable_length () == 0) {
5276 if (only_used_sources) {
5280 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5285 orig_sources[afs] = afs->path();
5286 orig_gain[afs] = afs->gain();
5288 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5289 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5290 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5293 progress->descend ((float)afs->readable_length () / total_size);
5297 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5298 afs->replace_file (new_path);
5299 afs->set_gain (ns->gain(), true);
5302 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5306 progress->ascend ();
5312 progress->set_progress (-1); // set to "archiving"
5313 progress->set_progress (0);
5316 /* index files relevant for this session */
5317 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5318 vector<string> files;
5320 size_t prefix_len = (*sd).path.size();
5321 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5325 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5327 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5328 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5329 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5331 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5332 std::string from = *i;
5335 string filename = Glib::path_get_basename (from);
5336 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5337 if (filename == ".DS_STORE") {
5342 if (from.find (audiofile_dir_string) != string::npos) {
5344 } else if (from.find (midifile_dir_string) != string::npos) {
5345 filemap[from] = make_new_media_path (from, name, name);
5346 } else if (from.find (videofile_dir_string) != string::npos) {
5347 filemap[from] = make_new_media_path (from, name, name);
5349 bool do_copy = true;
5350 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5351 if (from.find (*v) != string::npos) {
5356 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5357 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5364 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5370 /* write session file */
5372 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5374 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5377 save_default_options ();
5379 size_t prefix_len = _path.size();
5380 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5384 /* collect session-state files */
5385 vector<string> files;
5386 do_not_copy_extensions.clear ();
5387 do_not_copy_extensions.push_back (history_suffix);
5389 blacklist_dirs.clear ();
5390 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5392 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5393 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5394 std::string from = *i;
5395 bool do_copy = true;
5396 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5397 if (from.find (*v) != string::npos) {
5402 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5403 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5409 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5413 /* restore original values */
5416 set_snapshot_name (old_snapshot);
5417 (*_session_dir) = old_sd;
5421 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5422 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5424 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5425 i->first->replace_file (i->second);
5427 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5428 i->first->set_gain (i->second, true);
5431 int rv = ar.create (filemap);
5432 remove_directory (to_dir);
5438 Session::undo (uint32_t n)
5440 if (actively_recording()) {
5448 Session::redo (uint32_t n)
5450 if (actively_recording()) {