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));
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) {
1278 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1279 i->first->id().print (buf, sizeof (buf));
1280 can->add_property (X_("copy"), buf);
1281 i->second->id().print (buf, sizeof (buf));
1282 can->add_property (X_("original"), buf);
1283 ca->add_child_nocopy (*can);
1293 node->add_child_nocopy (_locations->get_state());
1296 Locations loc (*this);
1297 const bool was_dirty = dirty();
1298 // for a template, just create a new Locations, populate it
1299 // with the default start and end, and get the state for that.
1300 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1301 range->set (max_framepos, 0);
1303 XMLNode& locations_state = loc.get_state();
1305 if (ARDOUR::Profile->get_trx() && _locations) {
1306 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1307 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1308 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1309 locations_state.add_child_nocopy ((*i)->get_state ());
1313 node->add_child_nocopy (locations_state);
1315 /* adding a location above will have marked the session
1316 * dirty. This is an artifact, so fix it if the session wasn't
1321 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1325 child = node->add_child ("Bundles");
1327 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1328 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1329 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1331 child->add_child_nocopy (b->get_state());
1336 node->add_child_nocopy (_vca_manager->get_state());
1338 child = node->add_child ("Routes");
1340 boost::shared_ptr<RouteList> r = routes.reader ();
1342 RoutePublicOrderSorter cmp;
1343 RouteList public_order (*r);
1344 public_order.sort (cmp);
1346 /* the sort should have put the monitor out first */
1349 assert (_monitor_out == public_order.front());
1352 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1353 if (!(*i)->is_auditioner()) {
1355 child->add_child_nocopy ((*i)->get_state());
1357 child->add_child_nocopy ((*i)->get_template());
1363 playlists->add_state (node, full_state);
1365 child = node->add_child ("RouteGroups");
1366 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1367 child->add_child_nocopy ((*i)->get_state());
1371 XMLNode* gain_child = node->add_child ("Click");
1372 gain_child->add_child_nocopy (_click_io->state (full_state));
1373 gain_child->add_child_nocopy (_click_gain->state (full_state));
1377 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1378 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1382 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1383 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1386 node->add_child_nocopy (_speakers->get_state());
1387 node->add_child_nocopy (_tempo_map->get_state());
1388 node->add_child_nocopy (get_control_protocol_state());
1391 node->add_child_copy (*_extra_xml);
1395 Glib::Threads::Mutex::Lock lm (lua_lock);
1398 luabridge::LuaRef savedstate ((*_lua_save)());
1399 saved = savedstate.cast<std::string>();
1401 lua.collect_garbage ();
1404 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1405 std::string b64s (b64);
1408 XMLNode* script_node = new XMLNode (X_("Script"));
1409 script_node->add_property (X_("lua"), LUA_VERSION);
1410 script_node->add_content (b64s);
1411 node->add_child_nocopy (*script_node);
1418 Session::get_control_protocol_state ()
1420 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1421 return cpm.get_state();
1425 Session::set_state (const XMLNode& node, int version)
1430 XMLProperty const * prop;
1433 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1435 if (node.name() != X_("Session")) {
1436 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1440 if ((prop = node.property ("name")) != 0) {
1441 _name = prop->value ();
1444 if ((prop = node.property (X_("sample-rate"))) != 0) {
1446 _base_frame_rate = atoi (prop->value());
1447 _nominal_frame_rate = _base_frame_rate;
1449 assert (AudioEngine::instance()->running ());
1450 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1451 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1452 if (r.get_value_or (0)) {
1458 created_with = "unknown";
1459 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1460 if ((prop = child->property (X_("created-with"))) != 0) {
1461 created_with = prop->value ();
1465 setup_raid_path(_session_dir->root_path());
1467 if ((prop = node.property (X_("end-is-free"))) != 0) {
1468 _session_range_end_is_free = string_is_affirmative (prop->value());
1471 if ((prop = node.property (X_("id-counter"))) != 0) {
1473 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1474 ID::init_counter (x);
1476 /* old sessions used a timebased counter, so fake
1477 the startup ID counter based on a standard
1482 ID::init_counter (now);
1485 if ((prop = node.property (X_("name-counter"))) != 0) {
1486 init_name_id_counter (atoi (prop->value()));
1489 if ((prop = node.property (X_("event-counter"))) != 0) {
1490 Evoral::init_event_id_counter (atoi (prop->value()));
1493 if ((prop = node.property (X_("vca-counter"))) != 0) {
1495 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1496 VCA::set_next_vca_number (x);
1498 VCA::set_next_vca_number (1);
1501 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1502 _midi_ports->set_midi_port_states (child->children());
1505 IO::disable_connecting ();
1507 Stateful::save_extra_xml (node);
1509 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1510 load_options (*child);
1511 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1512 load_options (*child);
1514 error << _("Session: XML state has no options section") << endmsg;
1517 if (version >= 3000) {
1518 if ((child = find_named_node (node, "Metadata")) == 0) {
1519 warning << _("Session: XML state has no metadata section") << endmsg;
1520 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1525 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1526 _speakers->set_state (*child, version);
1529 if ((child = find_named_node (node, "Sources")) == 0) {
1530 error << _("Session: XML state has no sources section") << endmsg;
1532 } else if (load_sources (*child)) {
1536 if ((child = find_named_node (node, "TempoMap")) == 0) {
1537 error << _("Session: XML state has no Tempo Map section") << endmsg;
1539 } else if (_tempo_map->set_state (*child, version)) {
1543 if ((child = find_named_node (node, "Locations")) == 0) {
1544 error << _("Session: XML state has no locations section") << endmsg;
1546 } else if (_locations->set_state (*child, version)) {
1550 locations_changed ();
1552 if (_session_range_location) {
1553 AudioFileSource::set_header_position_offset (_session_range_location->start());
1556 if ((child = find_named_node (node, "Regions")) == 0) {
1557 error << _("Session: XML state has no Regions section") << endmsg;
1559 } else if (load_regions (*child)) {
1563 if ((child = find_named_node (node, "Playlists")) == 0) {
1564 error << _("Session: XML state has no playlists section") << endmsg;
1566 } else if (playlists->load (*this, *child)) {
1570 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1572 } else if (playlists->load_unused (*this, *child)) {
1576 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1577 if (load_compounds (*child)) {
1582 if (version >= 3000) {
1583 if ((child = find_named_node (node, "Bundles")) == 0) {
1584 warning << _("Session: XML state has no bundles section") << endmsg;
1587 /* We can't load Bundles yet as they need to be able
1588 to convert from port names to Port objects, which can't happen until
1590 _bundle_xml_node = new XMLNode (*child);
1594 if (version < 3000) {
1595 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1596 error << _("Session: XML state has no diskstreams section") << endmsg;
1598 } else if (load_diskstreams_2X (*child, version)) {
1603 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1604 _vca_manager->set_state (*child, version);
1607 if ((child = find_named_node (node, "Routes")) == 0) {
1608 error << _("Session: XML state has no routes section") << endmsg;
1610 } else if (load_routes (*child, version)) {
1614 /* Now that we have Routes and masters loaded, connect them if appropriate */
1616 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1618 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1619 _diskstreams_2X.clear ();
1621 if (version >= 3000) {
1623 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1624 error << _("Session: XML state has no route groups section") << endmsg;
1626 } else if (load_route_groups (*child, version)) {
1630 } else if (version < 3000) {
1632 if ((child = find_named_node (node, "EditGroups")) == 0) {
1633 error << _("Session: XML state has no edit groups section") << endmsg;
1635 } else if (load_route_groups (*child, version)) {
1639 if ((child = find_named_node (node, "MixGroups")) == 0) {
1640 error << _("Session: XML state has no mix groups section") << endmsg;
1642 } else if (load_route_groups (*child, version)) {
1647 if ((child = find_named_node (node, "Click")) == 0) {
1648 warning << _("Session: XML state has no click section") << endmsg;
1649 } else if (_click_io) {
1650 setup_click_state (&node);
1653 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1654 ControlProtocolManager::instance().set_state (*child, version);
1657 if ((child = find_named_node (node, "Script"))) {
1658 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1659 if (!(*n)->is_content ()) { continue; }
1661 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1663 Glib::Threads::Mutex::Lock lm (lua_lock);
1664 (*_lua_load)(std::string ((const char*)buf, size));
1665 } catch (luabridge::LuaException const& e) {
1666 cerr << "LuaException:" << e.what () << endl;
1672 update_route_record_state ();
1674 /* here beginneth the second phase ... */
1675 set_snapshot_name (_current_snapshot_name);
1677 StateReady (); /* EMIT SIGNAL */
1690 Session::load_routes (const XMLNode& node, int version)
1693 XMLNodeConstIterator niter;
1694 RouteList new_routes;
1696 nlist = node.children();
1700 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1702 boost::shared_ptr<Route> route;
1703 if (version < 3000) {
1704 route = XMLRouteFactory_2X (**niter, version);
1706 route = XMLRouteFactory (**niter, version);
1710 error << _("Session: cannot create Route from XML description.") << endmsg;
1714 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1716 new_routes.push_back (route);
1719 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1721 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1723 BootMessage (_("Finished adding tracks/busses"));
1728 boost::shared_ptr<Route>
1729 Session::XMLRouteFactory (const XMLNode& node, int version)
1731 boost::shared_ptr<Route> ret;
1733 if (node.name() != "Route") {
1737 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1739 DataType type = DataType::AUDIO;
1740 XMLProperty const * prop = node.property("default-type");
1743 type = DataType (prop->value());
1746 assert (type != DataType::NIL);
1750 boost::shared_ptr<Track> track;
1752 if (type == DataType::AUDIO) {
1753 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1755 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1758 if (track->init()) {
1762 if (track->set_state (node, version)) {
1766 BOOST_MARK_TRACK (track);
1770 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1771 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1773 if (r->init () == 0 && r->set_state (node, version) == 0) {
1774 BOOST_MARK_ROUTE (r);
1782 boost::shared_ptr<Route>
1783 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1785 boost::shared_ptr<Route> ret;
1787 if (node.name() != "Route") {
1791 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1793 ds_prop = node.property (X_("diskstream"));
1796 DataType type = DataType::AUDIO;
1797 XMLProperty const * prop = node.property("default-type");
1800 type = DataType (prop->value());
1803 assert (type != DataType::NIL);
1807 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1808 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1812 if (i == _diskstreams_2X.end()) {
1813 error << _("Could not find diskstream for route") << endmsg;
1814 return boost::shared_ptr<Route> ();
1817 boost::shared_ptr<Track> track;
1819 if (type == DataType::AUDIO) {
1820 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1822 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1825 if (track->init()) {
1829 if (track->set_state (node, version)) {
1833 track->set_diskstream (*i);
1835 BOOST_MARK_TRACK (track);
1839 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1840 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1842 if (r->init () == 0 && r->set_state (node, version) == 0) {
1843 BOOST_MARK_ROUTE (r);
1852 Session::load_regions (const XMLNode& node)
1855 XMLNodeConstIterator niter;
1856 boost::shared_ptr<Region> region;
1858 nlist = node.children();
1862 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1863 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1864 error << _("Session: cannot create Region from XML description.");
1865 XMLProperty const * name = (**niter).property("name");
1868 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1879 Session::load_compounds (const XMLNode& node)
1881 XMLNodeList calist = node.children();
1882 XMLNodeConstIterator caiter;
1883 XMLProperty const * caprop;
1885 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1886 XMLNode* ca = *caiter;
1890 if ((caprop = ca->property (X_("original"))) == 0) {
1893 orig_id = caprop->value();
1895 if ((caprop = ca->property (X_("copy"))) == 0) {
1898 copy_id = caprop->value();
1900 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1901 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1903 if (!orig || !copy) {
1904 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1910 RegionFactory::add_compound_association (orig, copy);
1917 Session::load_nested_sources (const XMLNode& node)
1920 XMLNodeConstIterator niter;
1922 nlist = node.children();
1924 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1925 if ((*niter)->name() == "Source") {
1927 /* it may already exist, so don't recreate it unnecessarily
1930 XMLProperty const * prop = (*niter)->property (X_("id"));
1932 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1936 ID source_id (prop->value());
1938 if (!source_by_id (source_id)) {
1941 SourceFactory::create (*this, **niter, true);
1943 catch (failed_constructor& err) {
1944 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1951 boost::shared_ptr<Region>
1952 Session::XMLRegionFactory (const XMLNode& node, bool full)
1954 XMLProperty const * type = node.property("type");
1958 const XMLNodeList& nlist = node.children();
1960 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1961 XMLNode *child = (*niter);
1962 if (child->name() == "NestedSource") {
1963 load_nested_sources (*child);
1967 if (!type || type->value() == "audio") {
1968 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1969 } else if (type->value() == "midi") {
1970 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1973 } catch (failed_constructor& err) {
1974 return boost::shared_ptr<Region> ();
1977 return boost::shared_ptr<Region> ();
1980 boost::shared_ptr<AudioRegion>
1981 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1983 XMLProperty const * prop;
1984 boost::shared_ptr<Source> source;
1985 boost::shared_ptr<AudioSource> as;
1987 SourceList master_sources;
1988 uint32_t nchans = 1;
1991 if (node.name() != X_("Region")) {
1992 return boost::shared_ptr<AudioRegion>();
1995 if ((prop = node.property (X_("channels"))) != 0) {
1996 nchans = atoi (prop->value().c_str());
1999 if ((prop = node.property ("name")) == 0) {
2000 cerr << "no name for this region\n";
2004 if ((prop = node.property (X_("source-0"))) == 0) {
2005 if ((prop = node.property ("source")) == 0) {
2006 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2007 return boost::shared_ptr<AudioRegion>();
2011 PBD::ID s_id (prop->value());
2013 if ((source = source_by_id (s_id)) == 0) {
2014 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2015 return boost::shared_ptr<AudioRegion>();
2018 as = boost::dynamic_pointer_cast<AudioSource>(source);
2020 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2021 return boost::shared_ptr<AudioRegion>();
2024 sources.push_back (as);
2026 /* pickup other channels */
2028 for (uint32_t n=1; n < nchans; ++n) {
2029 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2030 if ((prop = node.property (buf)) != 0) {
2032 PBD::ID id2 (prop->value());
2034 if ((source = source_by_id (id2)) == 0) {
2035 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2036 return boost::shared_ptr<AudioRegion>();
2039 as = boost::dynamic_pointer_cast<AudioSource>(source);
2041 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2042 return boost::shared_ptr<AudioRegion>();
2044 sources.push_back (as);
2048 for (uint32_t n = 0; n < nchans; ++n) {
2049 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2050 if ((prop = node.property (buf)) != 0) {
2052 PBD::ID id2 (prop->value());
2054 if ((source = source_by_id (id2)) == 0) {
2055 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2056 return boost::shared_ptr<AudioRegion>();
2059 as = boost::dynamic_pointer_cast<AudioSource>(source);
2061 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2062 return boost::shared_ptr<AudioRegion>();
2064 master_sources.push_back (as);
2069 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2071 /* a final detail: this is the one and only place that we know how long missing files are */
2073 if (region->whole_file()) {
2074 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2075 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2077 sfp->set_length (region->length());
2082 if (!master_sources.empty()) {
2083 if (master_sources.size() != nchans) {
2084 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2086 region->set_master_sources (master_sources);
2094 catch (failed_constructor& err) {
2095 return boost::shared_ptr<AudioRegion>();
2099 boost::shared_ptr<MidiRegion>
2100 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2102 XMLProperty const * prop;
2103 boost::shared_ptr<Source> source;
2104 boost::shared_ptr<MidiSource> ms;
2107 if (node.name() != X_("Region")) {
2108 return boost::shared_ptr<MidiRegion>();
2111 if ((prop = node.property ("name")) == 0) {
2112 cerr << "no name for this region\n";
2116 if ((prop = node.property (X_("source-0"))) == 0) {
2117 if ((prop = node.property ("source")) == 0) {
2118 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2119 return boost::shared_ptr<MidiRegion>();
2123 PBD::ID s_id (prop->value());
2125 if ((source = source_by_id (s_id)) == 0) {
2126 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2127 return boost::shared_ptr<MidiRegion>();
2130 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2132 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2133 return boost::shared_ptr<MidiRegion>();
2136 sources.push_back (ms);
2139 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2140 /* a final detail: this is the one and only place that we know how long missing files are */
2142 if (region->whole_file()) {
2143 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2144 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2146 sfp->set_length (region->length());
2154 catch (failed_constructor& err) {
2155 return boost::shared_ptr<MidiRegion>();
2160 Session::get_sources_as_xml ()
2163 XMLNode* node = new XMLNode (X_("Sources"));
2164 Glib::Threads::Mutex::Lock lm (source_lock);
2166 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2167 node->add_child_nocopy (i->second->get_state());
2174 Session::reset_write_sources (bool mark_write_complete, bool force)
2176 boost::shared_ptr<RouteList> rl = routes.reader();
2177 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2178 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2180 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2181 tr->reset_write_sources(mark_write_complete, force);
2182 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2188 Session::load_sources (const XMLNode& node)
2191 XMLNodeConstIterator niter;
2192 /* don't need this but it stops some
2193 * versions of gcc complaining about
2194 * discarded return values.
2196 boost::shared_ptr<Source> source;
2198 nlist = node.children();
2201 std::map<std::string, std::string> relocation;
2203 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2204 #ifdef PLATFORM_WINDOWS
2208 XMLNode srcnode (**niter);
2209 bool try_replace_abspath = true;
2213 #ifdef PLATFORM_WINDOWS
2214 // do not show "insert media" popups (files embedded from removable media).
2215 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2217 if ((source = XMLSourceFactory (srcnode)) == 0) {
2218 error << _("Session: cannot create Source from XML description.") << endmsg;
2220 #ifdef PLATFORM_WINDOWS
2221 SetErrorMode(old_mode);
2224 } catch (MissingSource& err) {
2225 #ifdef PLATFORM_WINDOWS
2226 SetErrorMode(old_mode);
2229 /* try previous abs path replacements first */
2230 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2231 std::string dir = Glib::path_get_dirname (err.path);
2232 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2233 if (rl != relocation.end ()) {
2234 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2235 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2236 srcnode.add_property ("origin", newpath);
2237 try_replace_abspath = false;
2244 _missing_file_replacement = "";
2246 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2247 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2248 PROGRAM_NAME) << endmsg;
2252 if (!no_questions_about_missing_files) {
2253 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2258 switch (user_choice) {
2260 /* user added a new search location
2261 * or selected a new absolute path,
2263 if (Glib::path_is_absolute (err.path)) {
2264 if (!_missing_file_replacement.empty ()) {
2265 /* replace origin, in XML */
2266 std::string newpath = Glib::build_filename (
2267 _missing_file_replacement, Glib::path_get_basename (err.path));
2268 srcnode.add_property ("origin", newpath);
2269 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2270 _missing_file_replacement = "";
2277 /* user asked to quit the entire session load */
2281 no_questions_about_missing_files = true;
2285 no_questions_about_missing_files = true;
2292 case DataType::AUDIO:
2293 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2296 case DataType::MIDI:
2297 /* The MIDI file is actually missing so
2298 * just create a new one in the same
2299 * location. Do not announce its
2303 if (!Glib::path_is_absolute (err.path)) {
2304 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2306 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2311 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2312 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2313 /* reset ID to match the missing one */
2314 source->set_id (**niter);
2315 /* Now we can announce it */
2316 SourceFactory::SourceCreated (source);
2327 boost::shared_ptr<Source>
2328 Session::XMLSourceFactory (const XMLNode& node)
2330 if (node.name() != "Source") {
2331 return boost::shared_ptr<Source>();
2335 /* note: do peak building in another thread when loading session state */
2336 return SourceFactory::create (*this, node, true);
2339 catch (failed_constructor& err) {
2340 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2341 return boost::shared_ptr<Source>();
2346 Session::save_template (string template_name, bool replace_existing)
2348 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2352 bool absolute_path = Glib::path_is_absolute (template_name);
2354 /* directory to put the template in */
2355 std::string template_dir_path;
2357 if (!absolute_path) {
2358 std::string user_template_dir(user_template_directory());
2360 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2361 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2362 user_template_dir, g_strerror (errno)) << endmsg;
2366 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2368 template_dir_path = template_name;
2371 if (!ARDOUR::Profile->get_trx()) {
2372 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2373 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2374 template_dir_path) << endmsg;
2378 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2379 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2380 template_dir_path, g_strerror (errno)) << endmsg;
2386 std::string template_file_path;
2388 if (ARDOUR::Profile->get_trx()) {
2389 template_file_path = template_name;
2391 if (absolute_path) {
2392 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2394 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2398 SessionSaveUnderway (); /* EMIT SIGNAL */
2403 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2404 tree.set_root (&get_template());
2407 if (!tree.write (template_file_path)) {
2408 error << _("template not saved") << endmsg;
2412 store_recent_templates (template_file_path);
2418 Session::refresh_disk_space ()
2420 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2422 Glib::Threads::Mutex::Lock lm (space_lock);
2424 /* get freespace on every FS that is part of the session path */
2426 _total_free_4k_blocks = 0;
2427 _total_free_4k_blocks_uncertain = false;
2429 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2430 #if defined(__NetBSD__)
2431 struct statvfs statfsbuf;
2433 statvfs (i->path.c_str(), &statfsbuf);
2435 struct statfs statfsbuf;
2437 statfs (i->path.c_str(), &statfsbuf);
2439 double const scale = statfsbuf.f_bsize / 4096.0;
2441 /* See if this filesystem is read-only */
2442 struct statvfs statvfsbuf;
2443 statvfs (i->path.c_str(), &statvfsbuf);
2445 /* f_bavail can be 0 if it is undefined for whatever
2446 filesystem we are looking at; Samba shares mounted
2447 via GVFS are an example of this.
2449 if (statfsbuf.f_bavail == 0) {
2450 /* block count unknown */
2452 i->blocks_unknown = true;
2453 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2454 /* read-only filesystem */
2456 i->blocks_unknown = false;
2458 /* read/write filesystem with known space */
2459 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2460 i->blocks_unknown = false;
2463 _total_free_4k_blocks += i->blocks;
2464 if (i->blocks_unknown) {
2465 _total_free_4k_blocks_uncertain = true;
2468 #elif defined PLATFORM_WINDOWS
2469 vector<string> scanned_volumes;
2470 vector<string>::iterator j;
2471 vector<space_and_path>::iterator i;
2472 DWORD nSectorsPerCluster, nBytesPerSector,
2473 nFreeClusters, nTotalClusters;
2477 _total_free_4k_blocks = 0;
2479 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2480 strncpy (disk_drive, (*i).path.c_str(), 3);
2484 volume_found = false;
2485 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2487 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2488 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2489 i->blocks = (uint32_t)(nFreeBytes / 4096);
2491 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2492 if (0 == j->compare(disk_drive)) {
2493 volume_found = true;
2498 if (!volume_found) {
2499 scanned_volumes.push_back(disk_drive);
2500 _total_free_4k_blocks += i->blocks;
2505 if (0 == _total_free_4k_blocks) {
2506 strncpy (disk_drive, path().c_str(), 3);
2509 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2511 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2512 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2513 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2520 Session::get_best_session_directory_for_new_audio ()
2522 vector<space_and_path>::iterator i;
2523 string result = _session_dir->root_path();
2525 /* handle common case without system calls */
2527 if (session_dirs.size() == 1) {
2531 /* OK, here's the algorithm we're following here:
2533 We want to select which directory to use for
2534 the next file source to be created. Ideally,
2535 we'd like to use a round-robin process so as to
2536 get maximum performance benefits from splitting
2537 the files across multiple disks.
2539 However, in situations without much diskspace, an
2540 RR approach may end up filling up a filesystem
2541 with new files while others still have space.
2542 Its therefore important to pay some attention to
2543 the freespace in the filesystem holding each
2544 directory as well. However, if we did that by
2545 itself, we'd keep creating new files in the file
2546 system with the most space until it was as full
2547 as all others, thus negating any performance
2548 benefits of this RAID-1 like approach.
2550 So, we use a user-configurable space threshold. If
2551 there are at least 2 filesystems with more than this
2552 much space available, we use RR selection between them.
2553 If not, then we pick the filesystem with the most space.
2555 This gets a good balance between the two
2559 refresh_disk_space ();
2561 int free_enough = 0;
2563 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2564 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2569 if (free_enough >= 2) {
2570 /* use RR selection process, ensuring that the one
2574 i = last_rr_session_dir;
2577 if (++i == session_dirs.end()) {
2578 i = session_dirs.begin();
2581 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2582 SessionDirectory sdir(i->path);
2583 if (sdir.create ()) {
2585 last_rr_session_dir = i;
2590 } while (i != last_rr_session_dir);
2594 /* pick FS with the most freespace (and that
2595 seems to actually work ...)
2598 vector<space_and_path> sorted;
2599 space_and_path_ascending_cmp cmp;
2601 sorted = session_dirs;
2602 sort (sorted.begin(), sorted.end(), cmp);
2604 for (i = sorted.begin(); i != sorted.end(); ++i) {
2605 SessionDirectory sdir(i->path);
2606 if (sdir.create ()) {
2608 last_rr_session_dir = i;
2618 Session::automation_dir () const
2620 return Glib::build_filename (_path, automation_dir_name);
2624 Session::analysis_dir () const
2626 return Glib::build_filename (_path, analysis_dir_name);
2630 Session::plugins_dir () const
2632 return Glib::build_filename (_path, plugins_dir_name);
2636 Session::externals_dir () const
2638 return Glib::build_filename (_path, externals_dir_name);
2642 Session::load_bundles (XMLNode const & node)
2644 XMLNodeList nlist = node.children();
2645 XMLNodeConstIterator niter;
2649 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2650 if ((*niter)->name() == "InputBundle") {
2651 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2652 } else if ((*niter)->name() == "OutputBundle") {
2653 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2655 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2664 Session::load_route_groups (const XMLNode& node, int version)
2666 XMLNodeList nlist = node.children();
2667 XMLNodeConstIterator niter;
2671 if (version >= 3000) {
2673 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2674 if ((*niter)->name() == "RouteGroup") {
2675 RouteGroup* rg = new RouteGroup (*this, "");
2676 add_route_group (rg);
2677 rg->set_state (**niter, version);
2681 } else if (version < 3000) {
2683 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2684 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2685 RouteGroup* rg = new RouteGroup (*this, "");
2686 add_route_group (rg);
2687 rg->set_state (**niter, version);
2696 state_file_filter (const string &str, void* /*arg*/)
2698 return (str.length() > strlen(statefile_suffix) &&
2699 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2703 remove_end(string state)
2705 string statename(state);
2707 string::size_type start,end;
2708 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2709 statename = statename.substr (start+1);
2712 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2713 end = statename.length();
2716 return string(statename.substr (0, end));
2720 Session::possible_states (string path)
2722 vector<string> states;
2723 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2725 transform(states.begin(), states.end(), states.begin(), remove_end);
2727 sort (states.begin(), states.end());
2733 Session::possible_states () const
2735 return possible_states(_path);
2739 Session::new_route_group (const std::string& name)
2741 RouteGroup* rg = NULL;
2743 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2744 if ((*i)->name () == name) {
2751 rg = new RouteGroup (*this, name);
2752 add_route_group (rg);
2758 Session::add_route_group (RouteGroup* g)
2760 _route_groups.push_back (g);
2761 route_group_added (g); /* EMIT SIGNAL */
2763 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2764 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2765 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2771 Session::remove_route_group (RouteGroup& rg)
2773 list<RouteGroup*>::iterator i;
2775 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2776 _route_groups.erase (i);
2779 route_group_removed (); /* EMIT SIGNAL */
2783 /** Set a new order for our route groups, without adding or removing any.
2784 * @param groups Route group list in the new order.
2787 Session::reorder_route_groups (list<RouteGroup*> groups)
2789 _route_groups = groups;
2791 route_groups_reordered (); /* EMIT SIGNAL */
2797 Session::route_group_by_name (string name)
2799 list<RouteGroup *>::iterator i;
2801 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2802 if ((*i)->name() == name) {
2810 Session::all_route_group() const
2812 return *_all_route_group;
2816 Session::add_commands (vector<Command*> const & cmds)
2818 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2824 Session::add_command (Command* const cmd)
2826 assert (_current_trans);
2827 DEBUG_UNDO_HISTORY (
2828 string_compose ("Current Undo Transaction %1, adding command: %2",
2829 _current_trans->name (),
2831 _current_trans->add_command (cmd);
2834 PBD::StatefulDiffCommand*
2835 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2837 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2843 Session::begin_reversible_command (const string& name)
2845 begin_reversible_command (g_quark_from_string (name.c_str ()));
2848 /** Begin a reversible command using a GQuark to identify it.
2849 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2850 * but there must be as many begin...()s as there are commit...()s.
2853 Session::begin_reversible_command (GQuark q)
2855 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2856 to hold all the commands that are committed. This keeps the order of
2857 commands correct in the history.
2860 if (_current_trans == 0) {
2861 DEBUG_UNDO_HISTORY (string_compose (
2862 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2864 /* start a new transaction */
2865 assert (_current_trans_quarks.empty ());
2866 _current_trans = new UndoTransaction();
2867 _current_trans->set_name (g_quark_to_string (q));
2869 DEBUG_UNDO_HISTORY (
2870 string_compose ("Begin Reversible Command, current transaction: %1",
2871 _current_trans->name ()));
2874 _current_trans_quarks.push_front (q);
2878 Session::abort_reversible_command ()
2880 if (_current_trans != 0) {
2881 DEBUG_UNDO_HISTORY (
2882 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2883 _current_trans->clear();
2884 delete _current_trans;
2886 _current_trans_quarks.clear();
2891 Session::commit_reversible_command (Command *cmd)
2893 assert (_current_trans);
2894 assert (!_current_trans_quarks.empty ());
2899 DEBUG_UNDO_HISTORY (
2900 string_compose ("Current Undo Transaction %1, adding command: %2",
2901 _current_trans->name (),
2903 _current_trans->add_command (cmd);
2906 DEBUG_UNDO_HISTORY (
2907 string_compose ("Commit Reversible Command, current transaction: %1",
2908 _current_trans->name ()));
2910 _current_trans_quarks.pop_front ();
2912 if (!_current_trans_quarks.empty ()) {
2913 DEBUG_UNDO_HISTORY (
2914 string_compose ("Commit Reversible Command, transaction is not "
2915 "top-level, current transaction: %1",
2916 _current_trans->name ()));
2917 /* the transaction we're committing is not the top-level one */
2921 if (_current_trans->empty()) {
2922 /* no commands were added to the transaction, so just get rid of it */
2923 DEBUG_UNDO_HISTORY (
2924 string_compose ("Commit Reversible Command, No commands were "
2925 "added to current transaction: %1",
2926 _current_trans->name ()));
2927 delete _current_trans;
2932 gettimeofday (&now, 0);
2933 _current_trans->set_timestamp (now);
2935 _history.add (_current_trans);
2940 accept_all_audio_files (const string& path, void* /*arg*/)
2942 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2946 if (!AudioFileSource::safe_audio_file_extension (path)) {
2954 accept_all_midi_files (const string& path, void* /*arg*/)
2956 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2960 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2961 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2962 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2966 accept_all_state_files (const string& path, void* /*arg*/)
2968 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2972 std::string const statefile_ext (statefile_suffix);
2973 if (path.length() >= statefile_ext.length()) {
2974 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2981 Session::find_all_sources (string path, set<string>& result)
2986 if (!tree.read (path)) {
2990 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2995 XMLNodeConstIterator niter;
2997 nlist = node->children();
3001 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3003 XMLProperty const * prop;
3005 if ((prop = (*niter)->property (X_("type"))) == 0) {
3009 DataType type (prop->value());
3011 if ((prop = (*niter)->property (X_("name"))) == 0) {
3015 if (Glib::path_is_absolute (prop->value())) {
3016 /* external file, ignore */
3024 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3025 result.insert (found_path);
3033 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3035 vector<string> state_files;
3037 string this_snapshot_path;
3043 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3044 ripped = ripped.substr (0, ripped.length() - 1);
3047 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3049 if (state_files.empty()) {
3054 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3055 this_snapshot_path += statefile_suffix;
3057 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3059 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3061 if (exclude_this_snapshot && *i == this_snapshot_path) {
3062 cerr << "\texcluded\n";
3067 if (find_all_sources (*i, result) < 0) {
3075 struct RegionCounter {
3076 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3077 AudioSourceList::iterator iter;
3078 boost::shared_ptr<Region> region;
3081 RegionCounter() : count (0) {}
3085 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3087 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3088 return r.get_value_or (1);
3092 Session::cleanup_regions ()
3094 bool removed = false;
3095 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3097 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3099 uint32_t used = playlists->region_use_count (i->second);
3101 if (used == 0 && !i->second->automatic ()) {
3102 boost::weak_ptr<Region> w = i->second;
3105 RegionFactory::map_remove (w);
3112 // re-check to remove parent references of compound regions
3113 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3114 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3118 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3119 if (0 == playlists->region_use_count (i->second)) {
3120 boost::weak_ptr<Region> w = i->second;
3122 RegionFactory::map_remove (w);
3129 /* dump the history list */
3136 Session::can_cleanup_peakfiles () const
3138 if (deletion_in_progress()) {
3141 if (!_writable || (_state_of_the_state & CannotSave)) {
3142 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3145 if (record_status() == Recording) {
3146 error << _("Cannot cleanup peak-files while recording") << endmsg;
3153 Session::cleanup_peakfiles ()
3155 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3160 assert (can_cleanup_peakfiles ());
3161 assert (!peaks_cleanup_in_progres());
3163 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3165 int timeout = 5000; // 5 seconds
3166 while (!SourceFactory::files_with_peaks.empty()) {
3167 Glib::usleep (1000);
3168 if (--timeout < 0) {
3169 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3170 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3175 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3176 boost::shared_ptr<AudioSource> as;
3177 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3178 as->close_peakfile();
3182 PBD::clear_directory (session_directory().peak_path());
3184 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3186 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3187 boost::shared_ptr<AudioSource> as;
3188 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3189 SourceFactory::setup_peakfile(as, true);
3196 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3198 pl->deep_sources (*all_sources);
3202 Session::cleanup_sources (CleanupReport& rep)
3204 // FIXME: needs adaptation to midi
3206 vector<boost::shared_ptr<Source> > dead_sources;
3209 vector<string> candidates;
3210 vector<string> unused;
3211 set<string> sources_used_by_all_snapshots;
3218 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3220 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3222 /* this is mostly for windows which doesn't allow file
3223 * renaming if the file is in use. But we don't special
3224 * case it because we need to know if this causes
3225 * problems, and the easiest way to notice that is to
3226 * keep it in place for all platforms.
3229 request_stop (false);
3231 _butler->wait_until_finished ();
3233 /* consider deleting all unused playlists */
3235 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3240 /* sync the "all regions" property of each playlist with its current state
3243 playlists->sync_all_regions_with_regions ();
3245 /* find all un-used sources */
3250 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3252 SourceMap::iterator tmp;
3257 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3261 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3262 dead_sources.push_back (i->second);
3263 i->second->drop_references ();
3269 /* build a list of all the possible audio directories for the session */
3271 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3272 SessionDirectory sdir ((*i).path);
3273 asp += sdir.sound_path();
3275 audio_path += asp.to_string();
3278 /* build a list of all the possible midi directories for the session */
3280 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3281 SessionDirectory sdir ((*i).path);
3282 msp += sdir.midi_path();
3284 midi_path += msp.to_string();
3286 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3287 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3289 /* add sources from all other snapshots as "used", but don't use this
3290 snapshot because the state file on disk still references sources we
3291 may have already dropped.
3294 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3296 /* Although the region factory has a list of all regions ever created
3297 * for this session, we're only interested in regions actually in
3298 * playlists right now. So merge all playlist regions lists together.
3300 * This will include the playlists used within compound regions.
3303 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3305 /* add our current source list
3308 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3309 boost::shared_ptr<FileSource> fs;
3310 SourceMap::iterator tmp = i;
3313 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3319 /* this is mostly for windows which doesn't allow file
3320 * renaming if the file is in use. But we do not special
3321 * case it because we need to know if this causes
3322 * problems, and the easiest way to notice that is to
3323 * keep it in place for all platforms.
3328 if (!fs->is_stub()) {
3330 /* Note that we're checking a list of all
3331 * sources across all snapshots with the list
3332 * of sources used by this snapshot.
3335 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3336 /* this source is in use by this snapshot */
3337 sources_used_by_all_snapshots.insert (fs->path());
3338 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3340 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3341 /* this source is NOT in use by this snapshot
3344 /* remove all related regions from RegionFactory master list
3347 RegionFactory::remove_regions_using_source (i->second);
3349 /* remove from our current source list
3350 * also. We may not remove it from
3351 * disk, because it may be used by
3352 * other snapshots, but it isn't used inside this
3353 * snapshot anymore, so we don't need a
3364 /* now check each candidate source to see if it exists in the list of
3365 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3368 cerr << "Candidates: " << candidates.size() << endl;
3369 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3371 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3376 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3378 tmppath1 = canonical_path (spath);
3379 tmppath2 = canonical_path ((*i));
3381 cerr << "\t => " << tmppath2 << endl;
3383 if (tmppath1 == tmppath2) {
3390 unused.push_back (spath);
3394 cerr << "Actually unused: " << unused.size() << endl;
3396 if (unused.empty()) {
3402 /* now try to move all unused files into the "dead" directory(ies) */
3404 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3409 /* don't move the file across filesystems, just
3410 stick it in the `dead_dir_name' directory
3411 on whichever filesystem it was already on.
3414 if ((*x).find ("/sounds/") != string::npos) {
3416 /* old school, go up 1 level */
3418 newpath = Glib::path_get_dirname (*x); // "sounds"
3419 newpath = Glib::path_get_dirname (newpath); // "session-name"
3423 /* new school, go up 4 levels */
3425 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3426 newpath = Glib::path_get_dirname (newpath); // "session-name"
3427 newpath = Glib::path_get_dirname (newpath); // "interchange"
3428 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3431 newpath = Glib::build_filename (newpath, dead_dir_name);
3433 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3434 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3438 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3440 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3442 /* the new path already exists, try versioning */
3444 char buf[PATH_MAX+1];
3448 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3451 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3452 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3456 if (version == 999) {
3457 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3461 newpath = newpath_v;
3466 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3467 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3468 newpath, g_strerror (errno)) << endmsg;
3472 /* see if there an easy to find peakfile for this file, and remove it.
3475 string base = Glib::path_get_basename (*x);
3476 base += "%A"; /* this is what we add for the channel suffix of all native files,
3477 or for the first channel of embedded files. it will miss
3478 some peakfiles for other channels
3480 string peakpath = construct_peak_filepath (base);
3482 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3483 if (::g_unlink (peakpath.c_str ()) != 0) {
3484 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3485 g_strerror (errno)) << endmsg;
3486 /* try to back out */
3487 ::g_rename (newpath.c_str (), _path.c_str ());
3492 rep.paths.push_back (*x);
3493 rep.space += statbuf.st_size;
3496 /* dump the history list */
3500 /* save state so we don't end up a session file
3501 referring to non-existent sources.
3508 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3514 Session::cleanup_trash_sources (CleanupReport& rep)
3516 // FIXME: needs adaptation for MIDI
3518 vector<space_and_path>::iterator i;
3524 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3526 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3528 clear_directory (dead_dir, &rep.space, &rep.paths);
3535 Session::set_dirty ()
3537 /* never mark session dirty during loading */
3539 if (_state_of_the_state & Loading) {
3543 bool was_dirty = dirty();
3545 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3548 DirtyChanged(); /* EMIT SIGNAL */
3553 Session::set_clean ()
3555 bool was_dirty = dirty();
3557 _state_of_the_state = Clean;
3560 DirtyChanged(); /* EMIT SIGNAL */
3565 Session::set_deletion_in_progress ()
3567 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3571 Session::clear_deletion_in_progress ()
3573 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3577 Session::add_controllable (boost::shared_ptr<Controllable> c)
3579 /* this adds a controllable to the list managed by the Session.
3580 this is a subset of those managed by the Controllable class
3581 itself, and represents the only ones whose state will be saved
3582 as part of the session.
3585 Glib::Threads::Mutex::Lock lm (controllables_lock);
3586 controllables.insert (c);
3589 struct null_deleter { void operator()(void const *) const {} };
3592 Session::remove_controllable (Controllable* c)
3594 if (_state_of_the_state & Deletion) {
3598 Glib::Threads::Mutex::Lock lm (controllables_lock);
3600 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3602 if (x != controllables.end()) {
3603 controllables.erase (x);
3607 boost::shared_ptr<Controllable>
3608 Session::controllable_by_id (const PBD::ID& id)
3610 Glib::Threads::Mutex::Lock lm (controllables_lock);
3612 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3613 if ((*i)->id() == id) {
3618 return boost::shared_ptr<Controllable>();
3621 boost::shared_ptr<Controllable>
3622 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3624 boost::shared_ptr<Controllable> c;
3625 boost::shared_ptr<Stripable> s;
3626 boost::shared_ptr<Route> r;
3628 switch (desc.top_level_type()) {
3629 case ControllableDescriptor::NamedRoute:
3631 std::string str = desc.top_level_name();
3633 if (str == "Master" || str == "master") {
3635 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3637 } else if (str == "auditioner") {
3640 s = route_by_name (desc.top_level_name());
3646 case ControllableDescriptor::PresentationOrderRoute:
3647 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3650 case ControllableDescriptor::PresentationOrderTrack:
3651 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3654 case ControllableDescriptor::PresentationOrderBus:
3655 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3658 case ControllableDescriptor::PresentationOrderVCA:
3659 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3662 case ControllableDescriptor::SelectionCount:
3663 s = route_by_selected_count (desc.selection_id());
3671 r = boost::dynamic_pointer_cast<Route> (s);
3673 switch (desc.subtype()) {
3674 case ControllableDescriptor::Gain:
3675 c = s->gain_control ();
3678 case ControllableDescriptor::Trim:
3679 c = s->trim_control ();
3682 case ControllableDescriptor::Solo:
3683 c = s->solo_control();
3686 case ControllableDescriptor::Mute:
3687 c = s->mute_control();
3690 case ControllableDescriptor::Recenable:
3691 c = s->rec_enable_control ();
3694 case ControllableDescriptor::PanDirection:
3695 c = s->pan_azimuth_control();
3698 case ControllableDescriptor::PanWidth:
3699 c = s->pan_width_control();
3702 case ControllableDescriptor::PanElevation:
3703 c = s->pan_elevation_control();
3706 case ControllableDescriptor::Balance:
3707 /* XXX simple pan control */
3710 case ControllableDescriptor::PluginParameter:
3712 uint32_t plugin = desc.target (0);
3713 uint32_t parameter_index = desc.target (1);
3715 /* revert to zero based counting */
3721 if (parameter_index > 0) {
3729 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3732 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3733 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3738 case ControllableDescriptor::SendGain: {
3739 uint32_t send = desc.target (0);
3746 c = r->send_level_controllable (send);
3751 /* relax and return a null pointer */
3759 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3762 Stateful::add_instant_xml (node, _path);
3765 if (write_to_config) {
3766 Config->add_instant_xml (node);
3771 Session::instant_xml (const string& node_name)
3773 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3774 if (get_disable_all_loaded_plugins ()) {
3778 return Stateful::instant_xml (node_name, _path);
3782 Session::save_history (string snapshot_name)
3790 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3791 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3795 if (snapshot_name.empty()) {
3796 snapshot_name = _current_snapshot_name;
3799 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3800 const string backup_filename = history_filename + backup_suffix;
3801 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3802 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3804 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3805 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3806 error << _("could not backup old history file, current history not saved") << endmsg;
3811 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3813 if (!tree.write (xml_path))
3815 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3817 if (g_remove (xml_path.c_str()) != 0) {
3818 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3819 xml_path, g_strerror (errno)) << endmsg;
3821 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3822 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3823 backup_path, g_strerror (errno)) << endmsg;
3833 Session::restore_history (string snapshot_name)
3837 if (snapshot_name.empty()) {
3838 snapshot_name = _current_snapshot_name;
3841 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3842 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3844 info << "Loading history from " << xml_path << endmsg;
3846 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3847 info << string_compose (_("%1: no history file \"%2\" for this session."),
3848 _name, xml_path) << endmsg;
3852 if (!tree.read (xml_path)) {
3853 error << string_compose (_("Could not understand session history file \"%1\""),
3854 xml_path) << endmsg;
3861 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3864 UndoTransaction* ut = new UndoTransaction ();
3867 ut->set_name(t->property("name")->value());
3868 stringstream ss(t->property("tv-sec")->value());
3870 ss.str(t->property("tv-usec")->value());
3872 ut->set_timestamp(tv);
3874 for (XMLNodeConstIterator child_it = t->children().begin();
3875 child_it != t->children().end(); child_it++)
3877 XMLNode *n = *child_it;
3880 if (n->name() == "MementoCommand" ||
3881 n->name() == "MementoUndoCommand" ||
3882 n->name() == "MementoRedoCommand") {
3884 if ((c = memento_command_factory(n))) {
3888 } else if (n->name() == "NoteDiffCommand") {
3889 PBD::ID id (n->property("midi-source")->value());
3890 boost::shared_ptr<MidiSource> midi_source =
3891 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3893 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3895 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3898 } else if (n->name() == "SysExDiffCommand") {
3900 PBD::ID id (n->property("midi-source")->value());
3901 boost::shared_ptr<MidiSource> midi_source =
3902 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3904 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3906 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3909 } else if (n->name() == "PatchChangeDiffCommand") {
3911 PBD::ID id (n->property("midi-source")->value());
3912 boost::shared_ptr<MidiSource> midi_source =
3913 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3915 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3917 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3920 } else if (n->name() == "StatefulDiffCommand") {
3921 if ((c = stateful_diff_command_factory (n))) {
3922 ut->add_command (c);
3925 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3936 Session::config_changed (std::string p, bool ours)
3942 if (p == "seamless-loop") {
3944 } else if (p == "rf-speed") {
3946 } else if (p == "auto-loop") {
3948 } else if (p == "session-monitoring") {
3950 } else if (p == "auto-input") {
3952 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3953 /* auto-input only makes a difference if we're rolling */
3954 set_track_monitor_input_status (!config.get_auto_input());
3957 } else if (p == "punch-in") {
3961 if ((location = _locations->auto_punch_location()) != 0) {
3963 if (config.get_punch_in ()) {
3964 replace_event (SessionEvent::PunchIn, location->start());
3966 remove_event (location->start(), SessionEvent::PunchIn);
3970 } else if (p == "punch-out") {
3974 if ((location = _locations->auto_punch_location()) != 0) {
3976 if (config.get_punch_out()) {
3977 replace_event (SessionEvent::PunchOut, location->end());
3979 clear_events (SessionEvent::PunchOut);
3983 } else if (p == "edit-mode") {
3985 Glib::Threads::Mutex::Lock lm (playlists->lock);
3987 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3988 (*i)->set_edit_mode (Config->get_edit_mode ());
3991 } else if (p == "use-video-sync") {
3993 waiting_for_sync_offset = config.get_use_video_sync();
3995 } else if (p == "mmc-control") {
3997 //poke_midi_thread ();
3999 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4001 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4003 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4005 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4007 } else if (p == "midi-control") {
4009 //poke_midi_thread ();
4011 } else if (p == "raid-path") {
4013 setup_raid_path (config.get_raid_path());
4015 } else if (p == "timecode-format") {
4019 } else if (p == "video-pullup") {
4023 } else if (p == "seamless-loop") {
4025 if (play_loop && transport_rolling()) {
4026 // to reset diskstreams etc
4027 request_play_loop (true);
4030 } else if (p == "rf-speed") {
4032 cumulative_rf_motion = 0;
4035 } else if (p == "click-sound") {
4037 setup_click_sounds (1);
4039 } else if (p == "click-emphasis-sound") {
4041 setup_click_sounds (-1);
4043 } else if (p == "clicking") {
4045 if (Config->get_clicking()) {
4046 if (_click_io && click_data) { // don't require emphasis data
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()) {