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"
53 #include "pbd/locale_guard.h"
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/basename.h"
67 #include "pbd/debug.h"
68 #include "pbd/enumwriter.h"
69 #include "pbd/error.h"
70 #include "pbd/file_archive.h"
71 #include "pbd/file_utils.h"
72 #include "pbd/pathexpand.h"
73 #include "pbd/pthread_utils.h"
74 #include "pbd/stacktrace.h"
75 #include "pbd/types_convert.h"
76 #include "pbd/localtime_r.h"
77 #include "pbd/unwind.h"
79 #include "ardour/amp.h"
80 #include "ardour/async_midi_port.h"
81 #include "ardour/audio_diskstream.h"
82 #include "ardour/audio_track.h"
83 #include "ardour/audioengine.h"
84 #include "ardour/audiofilesource.h"
85 #include "ardour/audioregion.h"
86 #include "ardour/auditioner.h"
87 #include "ardour/automation_control.h"
88 #include "ardour/boost_debug.h"
89 #include "ardour/butler.h"
90 #include "ardour/controllable_descriptor.h"
91 #include "ardour/control_protocol_manager.h"
92 #include "ardour/directory_names.h"
93 #include "ardour/filename_extensions.h"
94 #include "ardour/graph.h"
95 #include "ardour/location.h"
97 #include "ardour/lv2_plugin.h"
99 #include "ardour/midi_model.h"
100 #include "ardour/midi_patch_manager.h"
101 #include "ardour/midi_region.h"
102 #include "ardour/midi_scene_changer.h"
103 #include "ardour/midi_source.h"
104 #include "ardour/midi_track.h"
105 #include "ardour/pannable.h"
106 #include "ardour/playlist_factory.h"
107 #include "ardour/playlist_source.h"
108 #include "ardour/port.h"
109 #include "ardour/processor.h"
110 #include "ardour/progress.h"
111 #include "ardour/profile.h"
112 #include "ardour/proxy_controllable.h"
113 #include "ardour/recent_sessions.h"
114 #include "ardour/region_factory.h"
115 #include "ardour/revision.h"
116 #include "ardour/route_group.h"
117 #include "ardour/send.h"
118 #include "ardour/selection.h"
119 #include "ardour/session.h"
120 #include "ardour/session_directory.h"
121 #include "ardour/session_metadata.h"
122 #include "ardour/session_playlists.h"
123 #include "ardour/session_state_utils.h"
124 #include "ardour/silentfilesource.h"
125 #include "ardour/sndfilesource.h"
126 #include "ardour/source_factory.h"
127 #include "ardour/speakers.h"
128 #include "ardour/template_utils.h"
129 #include "ardour/tempo.h"
130 #include "ardour/ticker.h"
131 #include "ardour/types_convert.h"
132 #include "ardour/user_bundle.h"
133 #include "ardour/vca.h"
134 #include "ardour/vca_manager.h"
136 #include "control_protocol/control_protocol.h"
138 #include "LuaBridge/LuaBridge.h"
140 #include "pbd/i18n.h"
144 using namespace ARDOUR;
147 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
150 Session::pre_engine_init (string fullpath)
152 if (fullpath.empty()) {
154 throw failed_constructor();
157 /* discover canonical fullpath */
159 _path = canonical_path(fullpath);
162 if (Profile->get_trx() ) {
163 // Waves TracksLive has a usecase of session replacement with a new one.
164 // We should check session state file (<session_name>.ardour) existance
165 // to determine if the session is new or not
167 string full_session_name = Glib::build_filename( fullpath, _name );
168 full_session_name += statefile_suffix;
170 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
172 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
175 /* finish initialization that can't be done in a normal C++ constructor
179 timerclear (&last_mmc_step);
180 g_atomic_int_set (&processing_prohibited, 0);
181 g_atomic_int_set (&_record_status, Disabled);
182 g_atomic_int_set (&_playback_load, 100);
183 g_atomic_int_set (&_capture_load, 100);
185 _all_route_group->set_active (true, this);
186 interpolation.add_channel_to (0, 0);
188 if (config.get_use_video_sync()) {
189 waiting_for_sync_offset = true;
191 waiting_for_sync_offset = false;
194 last_rr_session_dir = session_dirs.begin();
196 set_history_depth (Config->get_history_depth());
198 /* default: assume simple stereo speaker configuration */
200 _speakers->setup_default_speakers (2);
202 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
203 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
204 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
205 add_controllable (_solo_cut_control);
207 /* These are all static "per-class" signals */
209 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
210 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
211 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
212 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
213 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
215 /* stop IO objects from doing stuff until we're ready for them */
217 Delivery::disable_panners ();
218 IO::disable_connecting ();
222 Session::post_engine_init ()
224 BootMessage (_("Set block size and sample rate"));
226 set_block_size (_engine.samples_per_cycle());
227 set_frame_rate (_engine.sample_rate());
229 BootMessage (_("Using configuration"));
231 _midi_ports = new MidiPortManager;
233 MIDISceneChanger* msc;
235 _scene_changer = msc = new MIDISceneChanger (*this);
236 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
237 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
239 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
240 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
242 setup_midi_machine_control ();
244 if (_butler->start_thread()) {
245 error << _("Butler did not start") << endmsg;
249 if (start_midi_thread ()) {
250 error << _("MIDI I/O thread did not start") << endmsg;
254 setup_click_sounds (0);
255 setup_midi_control ();
257 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
258 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
261 /* tempo map requires sample rate knowledge */
264 _tempo_map = new TempoMap (_current_frame_rate);
265 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
266 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
268 /* MidiClock requires a tempo map */
271 midi_clock = new MidiClockTicker ();
272 midi_clock->set_session (this);
274 /* crossfades require sample rate knowledge */
276 SndFileSource::setup_standard_crossfades (*this, frame_rate());
277 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
278 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
280 AudioDiskstream::allocate_working_buffers();
281 refresh_disk_space ();
283 /* we're finally ready to call set_state() ... all objects have
284 * been created, the engine is running.
288 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
289 error << _("Could not set session state from XML") << endmsg;
293 // set_state() will call setup_raid_path(), but if it's a new session we need
294 // to call setup_raid_path() here.
295 setup_raid_path (_path);
300 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
301 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
303 Config->map_parameters (ff);
304 config.map_parameters (ft);
305 _butler->map_parameters ();
307 /* Reset all panners */
309 Delivery::reset_panners ();
311 /* this will cause the CPM to instantiate any protocols that are in use
312 * (or mandatory), which will pass it this Session, and then call
313 * set_state() on each instantiated protocol to match stored state.
316 ControlProtocolManager::instance().set_session (this);
318 /* This must be done after the ControlProtocolManager set_session above,
319 as it will set states for ports which the ControlProtocolManager creates.
322 // XXX set state of MIDI::Port's
323 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
325 /* And this must be done after the MIDI::Manager::set_port_states as
326 * it will try to make connections whose details are loaded by set_port_states.
331 /* Let control protocols know that we are now all connected, so they
332 * could start talking to surfaces if they want to.
335 ControlProtocolManager::instance().midi_connectivity_established ();
337 if (_is_new && !no_auto_connect()) {
338 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
339 auto_connect_master_bus ();
342 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
344 /* update latencies */
346 initialize_latencies ();
348 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
349 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
350 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
352 } catch (AudioEngine::PortRegistrationFailure& err) {
353 /* handle this one in a different way than all others, so that its clear what happened */
354 error << err.what() << endmsg;
356 } catch (std::exception const & e) {
357 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
360 error << _("Unknown exception during session setup") << endmsg;
364 BootMessage (_("Reset Remote Controls"));
366 // send_full_time_code (0);
367 _engine.transport_locate (0);
369 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
370 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
372 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
375 /* initial program change will be delivered later; see ::config_changed() */
377 _state_of_the_state = Clean;
379 Port::set_connecting_blocked (false);
381 DirtyChanged (); /* EMIT SIGNAL */
385 } else if (state_was_pending) {
387 remove_pending_capture_state ();
388 state_was_pending = false;
391 /* Now, finally, we can fill the playback buffers */
393 BootMessage (_("Filling playback buffers"));
395 boost::shared_ptr<RouteList> rl = routes.reader();
396 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
397 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
398 if (trk && !trk->hidden()) {
399 trk->seek (_transport_frame, true);
407 Session::session_loaded ()
411 _state_of_the_state = Clean;
413 DirtyChanged (); /* EMIT SIGNAL */
417 } else if (state_was_pending) {
419 remove_pending_capture_state ();
420 state_was_pending = false;
423 /* Now, finally, we can fill the playback buffers */
425 BootMessage (_("Filling playback buffers"));
426 force_locate (_transport_frame, false);
430 Session::raid_path () const
432 Searchpath raid_search_path;
434 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
435 raid_search_path += (*i).path;
438 return raid_search_path.to_string ();
442 Session::setup_raid_path (string path)
451 session_dirs.clear ();
453 Searchpath search_path(path);
454 Searchpath sound_search_path;
455 Searchpath midi_search_path;
457 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
459 sp.blocks = 0; // not needed
460 session_dirs.push_back (sp);
462 SessionDirectory sdir(sp.path);
464 sound_search_path += sdir.sound_path ();
465 midi_search_path += sdir.midi_path ();
468 // reset the round-robin soundfile path thingie
469 last_rr_session_dir = session_dirs.begin();
473 Session::path_is_within_session (const std::string& path)
475 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
476 if (PBD::path_is_within (i->path, path)) {
484 Session::ensure_subdirs ()
488 dir = session_directory().peak_path();
490 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
491 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
495 dir = session_directory().sound_path();
497 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
498 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
502 dir = session_directory().midi_path();
504 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
505 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
509 dir = session_directory().dead_path();
511 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
512 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
516 dir = session_directory().export_path();
518 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
519 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
523 dir = analysis_dir ();
525 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
526 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
530 dir = plugins_dir ();
532 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
533 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
537 dir = externals_dir ();
539 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
540 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
547 /** @param session_template directory containing session template, or empty.
548 * Caller must not hold process lock.
551 Session::create (const string& session_template, BusProfile* bus_profile)
553 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
554 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
558 if (ensure_subdirs ()) {
562 _writable = exists_and_writable (_path);
564 if (!session_template.empty()) {
565 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
567 FILE* in = g_fopen (in_path.c_str(), "rb");
570 /* no need to call legalize_for_path() since the string
571 * in session_template is already a legal path name
573 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
575 FILE* out = g_fopen (out_path.c_str(), "wb");
579 stringstream new_session;
582 size_t charsRead = fread (buf, sizeof(char), 1024, in);
585 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
590 if (charsRead == 0) {
593 new_session.write (buf, charsRead);
597 string file_contents = new_session.str();
598 size_t writeSize = file_contents.length();
599 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
600 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
608 if (!ARDOUR::Profile->get_trx()) {
609 /* Copy plugin state files from template to new session */
610 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
611 copy_recurse (template_plugins, plugins_dir ());
617 error << string_compose (_("Could not open %1 for writing session template"), out_path)
624 error << string_compose (_("Could not open session template %1 for reading"), in_path)
631 if (Profile->get_trx()) {
633 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
634 * Remember that this is a brand new session. Sessions
635 * loaded from saved state will get this range from the saved state.
638 set_session_range_location (0, 0);
640 /* Initial loop location, from absolute zero, length 10 seconds */
642 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
643 _locations->add (loc, true);
644 set_auto_loop_location (loc);
647 _state_of_the_state = Clean;
649 /* set up Master Out and Monitor Out if necessary */
654 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
656 // Waves Tracks: always create master bus for Tracks
657 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
658 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
666 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
667 r->input()->ensure_io (count, false, this);
668 r->output()->ensure_io (count, false, this);
674 /* prohibit auto-connect to master, because there isn't one */
675 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
679 add_routes (rl, false, false, false, PresentationInfo::max_order);
682 // Waves Tracks: Skip this. Always use autoconnection for Tracks
683 if (!ARDOUR::Profile->get_trx()) {
685 /* this allows the user to override settings with an environment variable.
688 if (no_auto_connect()) {
689 bus_profile->input_ac = AutoConnectOption (0);
690 bus_profile->output_ac = AutoConnectOption (0);
693 Config->set_input_auto_connect (bus_profile->input_ac);
694 Config->set_output_auto_connect (bus_profile->output_ac);
698 if (Config->get_use_monitor_bus() && bus_profile) {
699 add_monitor_section ();
706 Session::maybe_write_autosave()
708 if (dirty() && record_status() != Recording) {
709 save_state("", true);
714 Session::remove_pending_capture_state ()
716 std::string pending_state_file_path(_session_dir->root_path());
718 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
720 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
722 if (g_remove (pending_state_file_path.c_str()) != 0) {
723 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
724 pending_state_file_path, g_strerror (errno)) << endmsg;
728 /** Rename a state file.
729 * @param old_name Old snapshot name.
730 * @param new_name New snapshot name.
733 Session::rename_state (string old_name, string new_name)
735 if (old_name == _current_snapshot_name || old_name == _name) {
736 /* refuse to rename the current snapshot or the "main" one */
740 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
741 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
743 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
744 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
746 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
747 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
748 old_name, new_name, g_strerror(errno)) << endmsg;
752 /** Remove a state file.
753 * @param snapshot_name Snapshot name.
756 Session::remove_state (string snapshot_name)
758 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
759 // refuse to remove the current snapshot or the "main" one
763 std::string xml_path(_session_dir->root_path());
765 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
767 if (!create_backup_file (xml_path)) {
768 // don't remove it if a backup can't be made
769 // create_backup_file will log the error.
774 if (g_remove (xml_path.c_str()) != 0) {
775 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
776 xml_path, g_strerror (errno)) << endmsg;
780 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
782 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
784 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
787 std::string xml_path(_session_dir->root_path());
789 /* prevent concurrent saves from different threads */
791 Glib::Threads::Mutex::Lock lm (save_state_lock);
793 if (!_writable || (_state_of_the_state & CannotSave)) {
797 if (g_atomic_int_get(&_suspend_save)) {
801 _save_queued = false;
803 if (!_engine.connected ()) {
804 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"), PROGRAM_NAME)
810 const int64_t save_start_time = g_get_monotonic_time();
813 /* tell sources we're saving first, in case they write out to a new file
814 * which should be saved with the state rather than the old one */
815 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
817 i->second->session_saved();
818 } catch (Evoral::SMF::FileError& e) {
819 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
823 SessionSaveUnderway (); /* EMIT SIGNAL */
825 bool mark_as_clean = true;
827 if (!snapshot_name.empty() && !switch_to_snapshot) {
828 mark_as_clean = false;
832 mark_as_clean = false;
833 tree.set_root (&get_template());
835 tree.set_root (&get_state());
838 if (snapshot_name.empty()) {
839 snapshot_name = _current_snapshot_name;
840 } else if (switch_to_snapshot) {
841 set_snapshot_name (snapshot_name);
844 assert (!snapshot_name.empty());
848 /* proper save: use statefile_suffix (.ardour in English) */
850 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
852 /* make a backup copy of the old file */
854 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
855 // create_backup_file will log the error
861 /* pending save: use pending_suffix (.pending in English) */
862 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
865 std::string tmp_path(_session_dir->root_path());
866 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
868 cerr << "actually writing state to " << tmp_path << endl;
870 if (!tree.write (tmp_path)) {
871 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
872 if (g_remove (tmp_path.c_str()) != 0) {
873 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
874 tmp_path, g_strerror (errno)) << endmsg;
880 cerr << "renaming state to " << xml_path << endl;
882 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
883 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
884 tmp_path, xml_path, g_strerror(errno)) << endmsg;
885 if (g_remove (tmp_path.c_str()) != 0) {
886 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
887 tmp_path, g_strerror (errno)) << endmsg;
895 save_history (snapshot_name);
898 bool was_dirty = dirty();
900 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
903 DirtyChanged (); /* EMIT SIGNAL */
907 StateSaved (snapshot_name); /* EMIT SIGNAL */
911 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
912 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
918 Session::restore_state (string snapshot_name)
920 if (load_state (snapshot_name) == 0) {
921 set_state (*state_tree->root(), Stateful::loading_state_version);
928 Session::load_state (string snapshot_name)
933 state_was_pending = false;
935 /* check for leftover pending state from a crashed capture attempt */
937 std::string xmlpath(_session_dir->root_path());
938 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
940 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
942 /* there is pending state from a crashed capture attempt */
944 boost::optional<int> r = AskAboutPendingState();
945 if (r.get_value_or (1)) {
946 state_was_pending = true;
950 if (!state_was_pending) {
951 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
954 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
955 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
956 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
957 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
962 state_tree = new XMLTree;
966 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
968 if (!state_tree->read (xmlpath)) {
969 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
975 XMLNode const & root (*state_tree->root());
977 if (root.name() != X_("Session")) {
978 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
985 if (root.get_property ("version", version)) {
986 if (version.find ('.') != string::npos) {
987 /* old school version format */
988 if (version[0] == '2') {
989 Stateful::loading_state_version = 2000;
991 Stateful::loading_state_version = 3000;
994 Stateful::loading_state_version = string_to<int32_t>(version);
997 /* no version implies very old version of Ardour */
998 Stateful::loading_state_version = 1000;
1001 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1003 std::string backup_path(_session_dir->root_path());
1004 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1005 backup_path = Glib::build_filename (backup_path, backup_filename);
1007 // only create a backup for a given statefile version once
1009 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1011 VersionMismatch (xmlpath, backup_path);
1013 if (!copy_file (xmlpath, backup_path)) {;
1019 save_snapshot_name (snapshot_name);
1025 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());
1132 struct route_id_compare {
1134 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1136 return r1->id () < r2->id ();
1142 Session::state (bool full_state)
1145 XMLNode* node = new XMLNode("Session");
1148 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1150 child = node->add_child ("ProgramVersion");
1151 child->set_property("created-with", created_with);
1153 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1154 child->set_property("modified-with", modified_with);
1156 /* store configuration settings */
1160 node->set_property ("name", _name);
1161 node->set_property ("sample-rate", _base_frame_rate);
1163 if (session_dirs.size() > 1) {
1167 vector<space_and_path>::iterator i = session_dirs.begin();
1168 vector<space_and_path>::iterator next;
1170 ++i; /* skip the first one */
1174 while (i != session_dirs.end()) {
1178 if (next != session_dirs.end()) {
1179 p += G_SEARCHPATH_SEPARATOR;
1188 child = node->add_child ("Path");
1189 child->add_content (p);
1191 node->set_property ("end-is-free", _session_range_end_is_free);
1194 /* save the ID counter */
1196 node->set_property ("id-counter", ID::counter());
1198 node->set_property ("name-counter", name_id_counter ());
1200 /* save the event ID counter */
1202 node->set_property ("event-counter", Evoral::event_id_counter());
1204 /* save the VCA counter */
1206 node->set_property ("vca-counter", VCA::get_next_vca_number());
1208 /* various options */
1210 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1211 if (!midi_port_nodes.empty()) {
1212 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1213 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1214 midi_port_stuff->add_child_nocopy (**n);
1216 node->add_child_nocopy (*midi_port_stuff);
1219 XMLNode& cfgxml (config.get_variables ());
1221 /* exclude search-paths from template */
1222 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1223 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1224 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1226 node->add_child_nocopy (cfgxml);
1228 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1230 child = node->add_child ("Sources");
1233 Glib::Threads::Mutex::Lock sl (source_lock);
1235 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1237 /* Don't save information about non-file Sources, or
1238 * about non-destructive file sources that are empty
1239 * and unused by any regions.
1242 boost::shared_ptr<FileSource> fs;
1244 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1246 if (!fs->destructive()) {
1247 if (fs->empty() && !fs->used()) {
1252 child->add_child_nocopy (siter->second->get_state());
1257 child = node->add_child ("Regions");
1260 Glib::Threads::Mutex::Lock rl (region_lock);
1261 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1262 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1263 boost::shared_ptr<Region> r = i->second;
1264 /* only store regions not attached to playlists */
1265 if (r->playlist() == 0) {
1266 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1267 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1269 child->add_child_nocopy (r->get_state ());
1274 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1276 if (!cassocs.empty()) {
1277 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1279 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1280 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1281 can->set_property (X_("copy"), i->first->id());
1282 can->set_property (X_("original"), i->second->id());
1283 ca->add_child_nocopy (*can);
1290 node->add_child_nocopy (_selection->get_state());
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 route_id_compare cmp;
1343 RouteList xml_node_order (*r);
1344 xml_node_order.sort (cmp);
1346 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1347 if (!(*i)->is_auditioner()) {
1349 child->add_child_nocopy ((*i)->get_state());
1351 child->add_child_nocopy ((*i)->get_template());
1357 playlists->add_state (node, full_state);
1359 child = node->add_child ("RouteGroups");
1360 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1361 child->add_child_nocopy ((*i)->get_state());
1365 XMLNode* gain_child = node->add_child ("Click");
1366 gain_child->add_child_nocopy (_click_io->state (full_state));
1367 gain_child->add_child_nocopy (_click_gain->state (full_state));
1371 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1372 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1376 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1377 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1380 node->add_child_nocopy (_speakers->get_state());
1381 node->add_child_nocopy (_tempo_map->get_state());
1382 node->add_child_nocopy (get_control_protocol_state());
1385 node->add_child_copy (*_extra_xml);
1389 Glib::Threads::Mutex::Lock lm (lua_lock);
1392 luabridge::LuaRef savedstate ((*_lua_save)());
1393 saved = savedstate.cast<std::string>();
1395 lua.collect_garbage ();
1398 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1399 std::string b64s (b64);
1402 XMLNode* script_node = new XMLNode (X_("Script"));
1403 script_node->set_property (X_("lua"), LUA_VERSION);
1404 script_node->add_content (b64s);
1405 node->add_child_nocopy (*script_node);
1412 Session::get_control_protocol_state ()
1414 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1415 return cpm.get_state();
1419 Session::set_state (const XMLNode& node, int version)
1426 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1428 if (node.name() != X_("Session")) {
1429 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1433 node.get_property ("name", _name);
1435 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1437 _nominal_frame_rate = _base_frame_rate;
1439 assert (AudioEngine::instance()->running ());
1440 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1441 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1442 if (r.get_value_or (0)) {
1448 created_with = "unknown";
1449 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1450 child->get_property (X_("created-with"), created_with);
1453 setup_raid_path(_session_dir->root_path());
1455 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1458 if (node.get_property (X_("id-counter"), counter)) {
1459 ID::init_counter (counter);
1461 /* old sessions used a timebased counter, so fake
1462 * the startup ID counter based on a standard
1467 ID::init_counter (now);
1470 if (node.get_property (X_("name-counter"), counter)) {
1471 init_name_id_counter (counter);
1474 if (node.get_property (X_("event-counter"), counter)) {
1475 Evoral::init_event_id_counter (counter);
1478 if (node.get_property (X_("vca-counter"), counter)) {
1479 VCA::set_next_vca_number (counter);
1481 VCA::set_next_vca_number (1);
1484 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1485 _midi_ports->set_midi_port_states (child->children());
1488 IO::disable_connecting ();
1490 Stateful::save_extra_xml (node);
1492 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1493 load_options (*child);
1494 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1495 load_options (*child);
1497 error << _("Session: XML state has no options section") << endmsg;
1500 if (version >= 3000) {
1501 if ((child = find_named_node (node, "Metadata")) == 0) {
1502 warning << _("Session: XML state has no metadata section") << endmsg;
1503 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1508 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1509 _speakers->set_state (*child, version);
1512 if ((child = find_named_node (node, "Sources")) == 0) {
1513 error << _("Session: XML state has no sources section") << endmsg;
1515 } else if (load_sources (*child)) {
1519 if ((child = find_named_node (node, "TempoMap")) == 0) {
1520 error << _("Session: XML state has no Tempo Map section") << endmsg;
1522 } else if (_tempo_map->set_state (*child, version)) {
1526 if ((child = find_named_node (node, "Locations")) == 0) {
1527 error << _("Session: XML state has no locations section") << endmsg;
1529 } else if (_locations->set_state (*child, version)) {
1533 locations_changed ();
1535 if (_session_range_location) {
1536 AudioFileSource::set_header_position_offset (_session_range_location->start());
1539 if ((child = find_named_node (node, "Regions")) == 0) {
1540 error << _("Session: XML state has no Regions section") << endmsg;
1542 } else if (load_regions (*child)) {
1546 if ((child = find_named_node (node, "Playlists")) == 0) {
1547 error << _("Session: XML state has no playlists section") << endmsg;
1549 } else if (playlists->load (*this, *child)) {
1553 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1555 } else if (playlists->load_unused (*this, *child)) {
1559 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1560 if (load_compounds (*child)) {
1565 if (version >= 3000) {
1566 if ((child = find_named_node (node, "Bundles")) == 0) {
1567 warning << _("Session: XML state has no bundles section") << endmsg;
1570 /* We can't load Bundles yet as they need to be able
1571 * to convert from port names to Port objects, which can't happen until
1573 _bundle_xml_node = new XMLNode (*child);
1577 if (version < 3000) {
1578 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1579 error << _("Session: XML state has no diskstreams section") << endmsg;
1581 } else if (load_diskstreams_2X (*child, version)) {
1586 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1587 _vca_manager->set_state (*child, version);
1590 if ((child = find_named_node (node, "Routes")) == 0) {
1591 error << _("Session: XML state has no routes section") << endmsg;
1593 } else if (load_routes (*child, version)) {
1597 /* Now that we have Routes and masters loaded, connect them if appropriate */
1599 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1601 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1602 _diskstreams_2X.clear ();
1604 if (version >= 3000) {
1606 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1607 error << _("Session: XML state has no route groups section") << endmsg;
1609 } else if (load_route_groups (*child, version)) {
1613 } else if (version < 3000) {
1615 if ((child = find_named_node (node, "EditGroups")) == 0) {
1616 error << _("Session: XML state has no edit groups section") << endmsg;
1618 } else if (load_route_groups (*child, version)) {
1622 if ((child = find_named_node (node, "MixGroups")) == 0) {
1623 error << _("Session: XML state has no mix groups section") << endmsg;
1625 } else if (load_route_groups (*child, version)) {
1630 if ((child = find_named_node (node, "Click")) == 0) {
1631 warning << _("Session: XML state has no click section") << endmsg;
1632 } else if (_click_io) {
1633 setup_click_state (&node);
1636 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1637 ControlProtocolManager::instance().set_state (*child, version);
1640 if ((child = find_named_node (node, "Script"))) {
1641 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1642 if (!(*n)->is_content ()) { continue; }
1644 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1646 Glib::Threads::Mutex::Lock lm (lua_lock);
1647 (*_lua_load)(std::string ((const char*)buf, size));
1648 } catch (luabridge::LuaException const& e) {
1649 cerr << "LuaException:" << e.what () << endl;
1655 if ((child = find_named_node (node, X_("Selection")))) {
1656 _selection->set_state (*child, version);
1659 update_route_record_state ();
1661 /* here beginneth the second phase ... */
1662 set_snapshot_name (_current_snapshot_name);
1664 StateReady (); /* EMIT SIGNAL */
1677 Session::load_routes (const XMLNode& node, int version)
1680 XMLNodeConstIterator niter;
1681 RouteList new_routes;
1683 nlist = node.children();
1687 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1689 boost::shared_ptr<Route> route;
1690 if (version < 3000) {
1691 route = XMLRouteFactory_2X (**niter, version);
1693 route = XMLRouteFactory (**niter, version);
1697 error << _("Session: cannot create Route from XML description.") << endmsg;
1701 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1703 new_routes.push_back (route);
1706 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1708 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1710 BootMessage (_("Finished adding tracks/busses"));
1715 boost::shared_ptr<Route>
1716 Session::XMLRouteFactory (const XMLNode& node, int version)
1718 boost::shared_ptr<Route> ret;
1720 if (node.name() != "Route") {
1724 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1726 DataType type = DataType::AUDIO;
1727 node.get_property("default-type", type);
1729 assert (type != DataType::NIL);
1733 boost::shared_ptr<Track> track;
1735 if (type == DataType::AUDIO) {
1736 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1738 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1741 if (track->init()) {
1745 if (track->set_state (node, version)) {
1749 BOOST_MARK_TRACK (track);
1753 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1754 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1756 if (r->init () == 0 && r->set_state (node, version) == 0) {
1757 BOOST_MARK_ROUTE (r);
1765 boost::shared_ptr<Route>
1766 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1768 boost::shared_ptr<Route> ret;
1770 if (node.name() != "Route") {
1774 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1776 ds_prop = node.property (X_("diskstream"));
1779 DataType type = DataType::AUDIO;
1780 node.get_property("default-type", type);
1782 assert (type != DataType::NIL);
1786 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1787 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1791 if (i == _diskstreams_2X.end()) {
1792 error << _("Could not find diskstream for route") << endmsg;
1793 return boost::shared_ptr<Route> ();
1796 boost::shared_ptr<Track> track;
1798 if (type == DataType::AUDIO) {
1799 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1801 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1804 if (track->init()) {
1808 if (track->set_state (node, version)) {
1812 track->set_diskstream (*i);
1814 BOOST_MARK_TRACK (track);
1818 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1819 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1821 if (r->init () == 0 && r->set_state (node, version) == 0) {
1822 BOOST_MARK_ROUTE (r);
1831 Session::load_regions (const XMLNode& node)
1834 XMLNodeConstIterator niter;
1835 boost::shared_ptr<Region> region;
1837 nlist = node.children();
1841 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1842 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1843 error << _("Session: cannot create Region from XML description.");
1844 XMLProperty const * name = (**niter).property("name");
1847 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1858 Session::load_compounds (const XMLNode& node)
1860 XMLNodeList calist = node.children();
1861 XMLNodeConstIterator caiter;
1862 XMLProperty const * caprop;
1864 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1865 XMLNode* ca = *caiter;
1869 if ((caprop = ca->property (X_("original"))) == 0) {
1872 orig_id = caprop->value();
1874 if ((caprop = ca->property (X_("copy"))) == 0) {
1877 copy_id = caprop->value();
1879 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1880 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1882 if (!orig || !copy) {
1883 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1889 RegionFactory::add_compound_association (orig, copy);
1896 Session::load_nested_sources (const XMLNode& node)
1899 XMLNodeConstIterator niter;
1901 nlist = node.children();
1903 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1904 if ((*niter)->name() == "Source") {
1906 /* it may already exist, so don't recreate it unnecessarily
1909 XMLProperty const * prop = (*niter)->property (X_("id"));
1911 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1915 ID source_id (prop->value());
1917 if (!source_by_id (source_id)) {
1920 SourceFactory::create (*this, **niter, true);
1922 catch (failed_constructor& err) {
1923 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1930 boost::shared_ptr<Region>
1931 Session::XMLRegionFactory (const XMLNode& node, bool full)
1933 XMLProperty const * type = node.property("type");
1937 const XMLNodeList& nlist = node.children();
1939 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1940 XMLNode *child = (*niter);
1941 if (child->name() == "NestedSource") {
1942 load_nested_sources (*child);
1946 if (!type || type->value() == "audio") {
1947 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1948 } else if (type->value() == "midi") {
1949 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1952 } catch (failed_constructor& err) {
1953 return boost::shared_ptr<Region> ();
1956 return boost::shared_ptr<Region> ();
1959 boost::shared_ptr<AudioRegion>
1960 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1962 XMLProperty const * prop;
1963 boost::shared_ptr<Source> source;
1964 boost::shared_ptr<AudioSource> as;
1966 SourceList master_sources;
1967 uint32_t nchans = 1;
1970 if (node.name() != X_("Region")) {
1971 return boost::shared_ptr<AudioRegion>();
1974 node.get_property (X_("channels"), nchans);
1976 if ((prop = node.property ("name")) == 0) {
1977 cerr << "no name for this region\n";
1981 if ((prop = node.property (X_("source-0"))) == 0) {
1982 if ((prop = node.property ("source")) == 0) {
1983 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1984 return boost::shared_ptr<AudioRegion>();
1988 PBD::ID s_id (prop->value());
1990 if ((source = source_by_id (s_id)) == 0) {
1991 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1992 return boost::shared_ptr<AudioRegion>();
1995 as = boost::dynamic_pointer_cast<AudioSource>(source);
1997 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1998 return boost::shared_ptr<AudioRegion>();
2001 sources.push_back (as);
2003 /* pickup other channels */
2005 for (uint32_t n=1; n < nchans; ++n) {
2006 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2007 if ((prop = node.property (buf)) != 0) {
2009 PBD::ID id2 (prop->value());
2011 if ((source = source_by_id (id2)) == 0) {
2012 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2013 return boost::shared_ptr<AudioRegion>();
2016 as = boost::dynamic_pointer_cast<AudioSource>(source);
2018 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2019 return boost::shared_ptr<AudioRegion>();
2021 sources.push_back (as);
2025 for (uint32_t n = 0; n < nchans; ++n) {
2026 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2027 if ((prop = node.property (buf)) != 0) {
2029 PBD::ID id2 (prop->value());
2031 if ((source = source_by_id (id2)) == 0) {
2032 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2033 return boost::shared_ptr<AudioRegion>();
2036 as = boost::dynamic_pointer_cast<AudioSource>(source);
2038 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2039 return boost::shared_ptr<AudioRegion>();
2041 master_sources.push_back (as);
2046 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2048 /* a final detail: this is the one and only place that we know how long missing files are */
2050 if (region->whole_file()) {
2051 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2052 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2054 sfp->set_length (region->length());
2059 if (!master_sources.empty()) {
2060 if (master_sources.size() != nchans) {
2061 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2063 region->set_master_sources (master_sources);
2071 catch (failed_constructor& err) {
2072 return boost::shared_ptr<AudioRegion>();
2076 boost::shared_ptr<MidiRegion>
2077 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2079 XMLProperty const * prop;
2080 boost::shared_ptr<Source> source;
2081 boost::shared_ptr<MidiSource> ms;
2084 if (node.name() != X_("Region")) {
2085 return boost::shared_ptr<MidiRegion>();
2088 if ((prop = node.property ("name")) == 0) {
2089 cerr << "no name for this region\n";
2093 if ((prop = node.property (X_("source-0"))) == 0) {
2094 if ((prop = node.property ("source")) == 0) {
2095 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2096 return boost::shared_ptr<MidiRegion>();
2100 PBD::ID s_id (prop->value());
2102 if ((source = source_by_id (s_id)) == 0) {
2103 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2104 return boost::shared_ptr<MidiRegion>();
2107 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2109 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2110 return boost::shared_ptr<MidiRegion>();
2113 sources.push_back (ms);
2116 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2117 /* a final detail: this is the one and only place that we know how long missing files are */
2119 if (region->whole_file()) {
2120 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2121 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2123 sfp->set_length (region->length());
2131 catch (failed_constructor& err) {
2132 return boost::shared_ptr<MidiRegion>();
2137 Session::get_sources_as_xml ()
2140 XMLNode* node = new XMLNode (X_("Sources"));
2141 Glib::Threads::Mutex::Lock lm (source_lock);
2143 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2144 node->add_child_nocopy (i->second->get_state());
2151 Session::reset_write_sources (bool mark_write_complete, bool force)
2153 boost::shared_ptr<RouteList> rl = routes.reader();
2154 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2155 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2157 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2158 tr->reset_write_sources(mark_write_complete, force);
2159 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2165 Session::load_sources (const XMLNode& node)
2168 XMLNodeConstIterator niter;
2169 /* don't need this but it stops some
2170 * versions of gcc complaining about
2171 * discarded return values.
2173 boost::shared_ptr<Source> source;
2175 nlist = node.children();
2178 std::map<std::string, std::string> relocation;
2180 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2181 #ifdef PLATFORM_WINDOWS
2185 XMLNode srcnode (**niter);
2186 bool try_replace_abspath = true;
2190 #ifdef PLATFORM_WINDOWS
2191 // do not show "insert media" popups (files embedded from removable media).
2192 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2194 if ((source = XMLSourceFactory (srcnode)) == 0) {
2195 error << _("Session: cannot create Source from XML description.") << endmsg;
2197 #ifdef PLATFORM_WINDOWS
2198 SetErrorMode(old_mode);
2201 } catch (MissingSource& err) {
2202 #ifdef PLATFORM_WINDOWS
2203 SetErrorMode(old_mode);
2206 /* try previous abs path replacements first */
2207 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2208 std::string dir = Glib::path_get_dirname (err.path);
2209 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2210 if (rl != relocation.end ()) {
2211 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2212 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2213 srcnode.set_property ("origin", newpath);
2214 try_replace_abspath = false;
2221 _missing_file_replacement = "";
2223 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2224 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2225 PROGRAM_NAME) << endmsg;
2229 if (!no_questions_about_missing_files) {
2230 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2235 switch (user_choice) {
2237 /* user added a new search location
2238 * or selected a new absolute path,
2240 if (Glib::path_is_absolute (err.path)) {
2241 if (!_missing_file_replacement.empty ()) {
2242 /* replace origin, in XML */
2243 std::string newpath = Glib::build_filename (
2244 _missing_file_replacement, Glib::path_get_basename (err.path));
2245 srcnode.set_property ("origin", newpath);
2246 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2247 _missing_file_replacement = "";
2254 /* user asked to quit the entire session load */
2258 no_questions_about_missing_files = true;
2262 no_questions_about_missing_files = true;
2269 case DataType::AUDIO:
2270 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2273 case DataType::MIDI:
2274 /* The MIDI file is actually missing so
2275 * just create a new one in the same
2276 * location. Do not announce its
2280 if (!Glib::path_is_absolute (err.path)) {
2281 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2283 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2288 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2289 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2290 /* reset ID to match the missing one */
2291 source->set_id (**niter);
2292 /* Now we can announce it */
2293 SourceFactory::SourceCreated (source);
2304 boost::shared_ptr<Source>
2305 Session::XMLSourceFactory (const XMLNode& node)
2307 if (node.name() != "Source") {
2308 return boost::shared_ptr<Source>();
2312 /* note: do peak building in another thread when loading session state */
2313 return SourceFactory::create (*this, node, true);
2316 catch (failed_constructor& err) {
2317 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2318 return boost::shared_ptr<Source>();
2323 Session::save_template (string template_name, bool replace_existing)
2325 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2329 bool absolute_path = Glib::path_is_absolute (template_name);
2331 /* directory to put the template in */
2332 std::string template_dir_path;
2334 if (!absolute_path) {
2335 std::string user_template_dir(user_template_directory());
2337 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2338 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2339 user_template_dir, g_strerror (errno)) << endmsg;
2343 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2345 template_dir_path = template_name;
2348 if (!ARDOUR::Profile->get_trx()) {
2349 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2350 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2351 template_dir_path) << endmsg;
2355 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2356 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2357 template_dir_path, g_strerror (errno)) << endmsg;
2363 std::string template_file_path;
2365 if (ARDOUR::Profile->get_trx()) {
2366 template_file_path = template_name;
2368 if (absolute_path) {
2369 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2371 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2375 SessionSaveUnderway (); /* EMIT SIGNAL */
2380 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2381 tree.set_root (&get_template());
2384 if (!tree.write (template_file_path)) {
2385 error << _("template not saved") << endmsg;
2389 store_recent_templates (template_file_path);
2395 Session::refresh_disk_space ()
2397 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2399 Glib::Threads::Mutex::Lock lm (space_lock);
2401 /* get freespace on every FS that is part of the session path */
2403 _total_free_4k_blocks = 0;
2404 _total_free_4k_blocks_uncertain = false;
2406 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2407 #if defined(__NetBSD__)
2408 struct statvfs statfsbuf;
2410 statvfs (i->path.c_str(), &statfsbuf);
2412 struct statfs statfsbuf;
2414 statfs (i->path.c_str(), &statfsbuf);
2416 double const scale = statfsbuf.f_bsize / 4096.0;
2418 /* See if this filesystem is read-only */
2419 struct statvfs statvfsbuf;
2420 statvfs (i->path.c_str(), &statvfsbuf);
2422 /* f_bavail can be 0 if it is undefined for whatever
2423 filesystem we are looking at; Samba shares mounted
2424 via GVFS are an example of this.
2426 if (statfsbuf.f_bavail == 0) {
2427 /* block count unknown */
2429 i->blocks_unknown = true;
2430 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2431 /* read-only filesystem */
2433 i->blocks_unknown = false;
2435 /* read/write filesystem with known space */
2436 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2437 i->blocks_unknown = false;
2440 _total_free_4k_blocks += i->blocks;
2441 if (i->blocks_unknown) {
2442 _total_free_4k_blocks_uncertain = true;
2445 #elif defined PLATFORM_WINDOWS
2446 vector<string> scanned_volumes;
2447 vector<string>::iterator j;
2448 vector<space_and_path>::iterator i;
2449 DWORD nSectorsPerCluster, nBytesPerSector,
2450 nFreeClusters, nTotalClusters;
2454 _total_free_4k_blocks = 0;
2456 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2457 strncpy (disk_drive, (*i).path.c_str(), 3);
2461 volume_found = false;
2462 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2464 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2465 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2466 i->blocks = (uint32_t)(nFreeBytes / 4096);
2468 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2469 if (0 == j->compare(disk_drive)) {
2470 volume_found = true;
2475 if (!volume_found) {
2476 scanned_volumes.push_back(disk_drive);
2477 _total_free_4k_blocks += i->blocks;
2482 if (0 == _total_free_4k_blocks) {
2483 strncpy (disk_drive, path().c_str(), 3);
2486 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2488 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2489 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2490 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2497 Session::get_best_session_directory_for_new_audio ()
2499 vector<space_and_path>::iterator i;
2500 string result = _session_dir->root_path();
2502 /* handle common case without system calls */
2504 if (session_dirs.size() == 1) {
2508 /* OK, here's the algorithm we're following here:
2510 We want to select which directory to use for
2511 the next file source to be created. Ideally,
2512 we'd like to use a round-robin process so as to
2513 get maximum performance benefits from splitting
2514 the files across multiple disks.
2516 However, in situations without much diskspace, an
2517 RR approach may end up filling up a filesystem
2518 with new files while others still have space.
2519 Its therefore important to pay some attention to
2520 the freespace in the filesystem holding each
2521 directory as well. However, if we did that by
2522 itself, we'd keep creating new files in the file
2523 system with the most space until it was as full
2524 as all others, thus negating any performance
2525 benefits of this RAID-1 like approach.
2527 So, we use a user-configurable space threshold. If
2528 there are at least 2 filesystems with more than this
2529 much space available, we use RR selection between them.
2530 If not, then we pick the filesystem with the most space.
2532 This gets a good balance between the two
2536 refresh_disk_space ();
2538 int free_enough = 0;
2540 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2541 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2546 if (free_enough >= 2) {
2547 /* use RR selection process, ensuring that the one
2551 i = last_rr_session_dir;
2554 if (++i == session_dirs.end()) {
2555 i = session_dirs.begin();
2558 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2559 SessionDirectory sdir(i->path);
2560 if (sdir.create ()) {
2562 last_rr_session_dir = i;
2567 } while (i != last_rr_session_dir);
2571 /* pick FS with the most freespace (and that
2572 seems to actually work ...)
2575 vector<space_and_path> sorted;
2576 space_and_path_ascending_cmp cmp;
2578 sorted = session_dirs;
2579 sort (sorted.begin(), sorted.end(), cmp);
2581 for (i = sorted.begin(); i != sorted.end(); ++i) {
2582 SessionDirectory sdir(i->path);
2583 if (sdir.create ()) {
2585 last_rr_session_dir = i;
2595 Session::automation_dir () const
2597 return Glib::build_filename (_path, automation_dir_name);
2601 Session::analysis_dir () const
2603 return Glib::build_filename (_path, analysis_dir_name);
2607 Session::plugins_dir () const
2609 return Glib::build_filename (_path, plugins_dir_name);
2613 Session::externals_dir () const
2615 return Glib::build_filename (_path, externals_dir_name);
2619 Session::load_bundles (XMLNode const & node)
2621 XMLNodeList nlist = node.children();
2622 XMLNodeConstIterator niter;
2626 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2627 if ((*niter)->name() == "InputBundle") {
2628 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2629 } else if ((*niter)->name() == "OutputBundle") {
2630 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2632 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2641 Session::load_route_groups (const XMLNode& node, int version)
2643 XMLNodeList nlist = node.children();
2644 XMLNodeConstIterator niter;
2648 if (version >= 3000) {
2650 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2651 if ((*niter)->name() == "RouteGroup") {
2652 RouteGroup* rg = new RouteGroup (*this, "");
2653 add_route_group (rg);
2654 rg->set_state (**niter, version);
2658 } else if (version < 3000) {
2660 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2661 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2662 RouteGroup* rg = new RouteGroup (*this, "");
2663 add_route_group (rg);
2664 rg->set_state (**niter, version);
2673 state_file_filter (const string &str, void* /*arg*/)
2675 return (str.length() > strlen(statefile_suffix) &&
2676 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2680 remove_end(string state)
2682 string statename(state);
2684 string::size_type start,end;
2685 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2686 statename = statename.substr (start+1);
2689 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2690 end = statename.length();
2693 return string(statename.substr (0, end));
2697 Session::possible_states (string path)
2699 vector<string> states;
2700 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2702 transform(states.begin(), states.end(), states.begin(), remove_end);
2704 sort (states.begin(), states.end());
2710 Session::possible_states () const
2712 return possible_states(_path);
2716 Session::new_route_group (const std::string& name)
2718 RouteGroup* rg = NULL;
2720 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2721 if ((*i)->name () == name) {
2728 rg = new RouteGroup (*this, name);
2729 add_route_group (rg);
2735 Session::add_route_group (RouteGroup* g)
2737 _route_groups.push_back (g);
2738 route_group_added (g); /* EMIT SIGNAL */
2740 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2741 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2742 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2748 Session::remove_route_group (RouteGroup& rg)
2750 list<RouteGroup*>::iterator i;
2752 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2753 _route_groups.erase (i);
2756 route_group_removed (); /* EMIT SIGNAL */
2760 /** Set a new order for our route groups, without adding or removing any.
2761 * @param groups Route group list in the new order.
2764 Session::reorder_route_groups (list<RouteGroup*> groups)
2766 _route_groups = groups;
2768 route_groups_reordered (); /* EMIT SIGNAL */
2774 Session::route_group_by_name (string name)
2776 list<RouteGroup *>::iterator i;
2778 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2779 if ((*i)->name() == name) {
2787 Session::all_route_group() const
2789 return *_all_route_group;
2793 Session::add_commands (vector<Command*> const & cmds)
2795 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2801 Session::add_command (Command* const cmd)
2803 assert (_current_trans);
2804 DEBUG_UNDO_HISTORY (
2805 string_compose ("Current Undo Transaction %1, adding command: %2",
2806 _current_trans->name (),
2808 _current_trans->add_command (cmd);
2811 PBD::StatefulDiffCommand*
2812 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2814 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2820 Session::begin_reversible_command (const string& name)
2822 begin_reversible_command (g_quark_from_string (name.c_str ()));
2825 /** Begin a reversible command using a GQuark to identify it.
2826 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2827 * but there must be as many begin...()s as there are commit...()s.
2830 Session::begin_reversible_command (GQuark q)
2832 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2833 to hold all the commands that are committed. This keeps the order of
2834 commands correct in the history.
2837 if (_current_trans == 0) {
2838 DEBUG_UNDO_HISTORY (string_compose (
2839 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2841 /* start a new transaction */
2842 assert (_current_trans_quarks.empty ());
2843 _current_trans = new UndoTransaction();
2844 _current_trans->set_name (g_quark_to_string (q));
2846 DEBUG_UNDO_HISTORY (
2847 string_compose ("Begin Reversible Command, current transaction: %1",
2848 _current_trans->name ()));
2851 _current_trans_quarks.push_front (q);
2855 Session::abort_reversible_command ()
2857 if (_current_trans != 0) {
2858 DEBUG_UNDO_HISTORY (
2859 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2860 _current_trans->clear();
2861 delete _current_trans;
2863 _current_trans_quarks.clear();
2868 Session::commit_reversible_command (Command *cmd)
2870 assert (_current_trans);
2871 assert (!_current_trans_quarks.empty ());
2876 DEBUG_UNDO_HISTORY (
2877 string_compose ("Current Undo Transaction %1, adding command: %2",
2878 _current_trans->name (),
2880 _current_trans->add_command (cmd);
2883 DEBUG_UNDO_HISTORY (
2884 string_compose ("Commit Reversible Command, current transaction: %1",
2885 _current_trans->name ()));
2887 _current_trans_quarks.pop_front ();
2889 if (!_current_trans_quarks.empty ()) {
2890 DEBUG_UNDO_HISTORY (
2891 string_compose ("Commit Reversible Command, transaction is not "
2892 "top-level, current transaction: %1",
2893 _current_trans->name ()));
2894 /* the transaction we're committing is not the top-level one */
2898 if (_current_trans->empty()) {
2899 /* no commands were added to the transaction, so just get rid of it */
2900 DEBUG_UNDO_HISTORY (
2901 string_compose ("Commit Reversible Command, No commands were "
2902 "added to current transaction: %1",
2903 _current_trans->name ()));
2904 delete _current_trans;
2909 gettimeofday (&now, 0);
2910 _current_trans->set_timestamp (now);
2912 _history.add (_current_trans);
2917 accept_all_audio_files (const string& path, void* /*arg*/)
2919 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2923 if (!AudioFileSource::safe_audio_file_extension (path)) {
2931 accept_all_midi_files (const string& path, void* /*arg*/)
2933 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2937 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
2938 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
2939 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2943 accept_all_state_files (const string& path, void* /*arg*/)
2945 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2949 std::string const statefile_ext (statefile_suffix);
2950 if (path.length() >= statefile_ext.length()) {
2951 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2958 Session::find_all_sources (string path, set<string>& result)
2963 if (!tree.read (path)) {
2967 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2972 XMLNodeConstIterator niter;
2974 nlist = node->children();
2978 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2980 XMLProperty const * prop;
2982 if ((prop = (*niter)->property (X_("type"))) == 0) {
2986 DataType type (prop->value());
2988 if ((prop = (*niter)->property (X_("name"))) == 0) {
2992 if (Glib::path_is_absolute (prop->value())) {
2993 /* external file, ignore */
3001 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3002 result.insert (found_path);
3010 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3012 vector<string> state_files;
3014 string this_snapshot_path;
3020 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3021 ripped = ripped.substr (0, ripped.length() - 1);
3024 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3026 if (state_files.empty()) {
3031 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3032 this_snapshot_path += statefile_suffix;
3034 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3036 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3038 if (exclude_this_snapshot && *i == this_snapshot_path) {
3039 cerr << "\texcluded\n";
3044 if (find_all_sources (*i, result) < 0) {
3052 struct RegionCounter {
3053 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3054 AudioSourceList::iterator iter;
3055 boost::shared_ptr<Region> region;
3058 RegionCounter() : count (0) {}
3062 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3064 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3065 return r.get_value_or (1);
3069 Session::cleanup_regions ()
3071 bool removed = false;
3072 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3074 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3076 uint32_t used = playlists->region_use_count (i->second);
3078 if (used == 0 && !i->second->automatic ()) {
3079 boost::weak_ptr<Region> w = i->second;
3082 RegionFactory::map_remove (w);
3089 // re-check to remove parent references of compound regions
3090 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3091 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3095 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3096 if (0 == playlists->region_use_count (i->second)) {
3097 boost::weak_ptr<Region> w = i->second;
3099 RegionFactory::map_remove (w);
3106 /* dump the history list */
3113 Session::can_cleanup_peakfiles () const
3115 if (deletion_in_progress()) {
3118 if (!_writable || (_state_of_the_state & CannotSave)) {
3119 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3122 if (record_status() == Recording) {
3123 error << _("Cannot cleanup peak-files while recording") << endmsg;
3130 Session::cleanup_peakfiles ()
3132 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3137 assert (can_cleanup_peakfiles ());
3138 assert (!peaks_cleanup_in_progres());
3140 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3142 int timeout = 5000; // 5 seconds
3143 while (!SourceFactory::files_with_peaks.empty()) {
3144 Glib::usleep (1000);
3145 if (--timeout < 0) {
3146 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3147 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3152 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3153 boost::shared_ptr<AudioSource> as;
3154 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3155 as->close_peakfile();
3159 PBD::clear_directory (session_directory().peak_path());
3161 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3163 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3164 boost::shared_ptr<AudioSource> as;
3165 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3166 SourceFactory::setup_peakfile(as, true);
3173 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3175 pl->deep_sources (*all_sources);
3179 Session::cleanup_sources (CleanupReport& rep)
3181 // FIXME: needs adaptation to midi
3183 vector<boost::shared_ptr<Source> > dead_sources;
3186 vector<string> candidates;
3187 vector<string> unused;
3188 set<string> sources_used_by_all_snapshots;
3195 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3197 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3199 /* this is mostly for windows which doesn't allow file
3200 * renaming if the file is in use. But we don't special
3201 * case it because we need to know if this causes
3202 * problems, and the easiest way to notice that is to
3203 * keep it in place for all platforms.
3206 request_stop (false);
3208 _butler->wait_until_finished ();
3210 /* consider deleting all unused playlists */
3212 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3217 /* sync the "all regions" property of each playlist with its current state */
3219 playlists->sync_all_regions_with_regions ();
3221 /* find all un-used sources */
3226 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3228 SourceMap::iterator tmp;
3233 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3237 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3238 dead_sources.push_back (i->second);
3239 i->second->drop_references ();
3245 /* build a list of all the possible audio directories for the session */
3247 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3248 SessionDirectory sdir ((*i).path);
3249 asp += sdir.sound_path();
3251 audio_path += asp.to_string();
3254 /* build a list of all the possible midi directories for the session */
3256 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3257 SessionDirectory sdir ((*i).path);
3258 msp += sdir.midi_path();
3260 midi_path += msp.to_string();
3262 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3263 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3265 /* add sources from all other snapshots as "used", but don't use this
3266 snapshot because the state file on disk still references sources we
3267 may have already dropped.
3270 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3272 /* Although the region factory has a list of all regions ever created
3273 * for this session, we're only interested in regions actually in
3274 * playlists right now. So merge all playlist regions lists together.
3276 * This will include the playlists used within compound regions.
3279 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3281 /* add our current source list
3284 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3285 boost::shared_ptr<FileSource> fs;
3286 SourceMap::iterator tmp = i;
3289 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3295 /* this is mostly for windows which doesn't allow file
3296 * renaming if the file is in use. But we do not special
3297 * case it because we need to know if this causes
3298 * problems, and the easiest way to notice that is to
3299 * keep it in place for all platforms.
3304 if (!fs->is_stub()) {
3306 /* Note that we're checking a list of all
3307 * sources across all snapshots with the list
3308 * of sources used by this snapshot.
3311 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3312 /* this source is in use by this snapshot */
3313 sources_used_by_all_snapshots.insert (fs->path());
3314 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3316 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3317 /* this source is NOT in use by this snapshot */
3319 /* remove all related regions from RegionFactory master list */
3321 RegionFactory::remove_regions_using_source (i->second);
3323 /* remove from our current source list
3324 * also. We may not remove it from
3325 * disk, because it may be used by
3326 * other snapshots, but it isn't used inside this
3327 * snapshot anymore, so we don't need a
3338 /* now check each candidate source to see if it exists in the list of
3339 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3342 cerr << "Candidates: " << candidates.size() << endl;
3343 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3345 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3350 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3352 tmppath1 = canonical_path (spath);
3353 tmppath2 = canonical_path ((*i));
3355 cerr << "\t => " << tmppath2 << endl;
3357 if (tmppath1 == tmppath2) {
3364 unused.push_back (spath);
3368 cerr << "Actually unused: " << unused.size() << endl;
3370 if (unused.empty()) {
3376 /* now try to move all unused files into the "dead" directory(ies) */
3378 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3383 /* don't move the file across filesystems, just
3384 * stick it in the `dead_dir_name' directory
3385 * on whichever filesystem it was already on.
3388 if ((*x).find ("/sounds/") != string::npos) {
3390 /* old school, go up 1 level */
3392 newpath = Glib::path_get_dirname (*x); // "sounds"
3393 newpath = Glib::path_get_dirname (newpath); // "session-name"
3397 /* new school, go up 4 levels */
3399 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3400 newpath = Glib::path_get_dirname (newpath); // "session-name"
3401 newpath = Glib::path_get_dirname (newpath); // "interchange"
3402 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3405 newpath = Glib::build_filename (newpath, dead_dir_name);
3407 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3408 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3412 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3414 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3416 /* the new path already exists, try versioning */
3418 char buf[PATH_MAX+1];
3422 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3425 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3426 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3430 if (version == 999) {
3431 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3435 newpath = newpath_v;
3440 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3441 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3442 newpath, g_strerror (errno)) << endmsg;
3446 /* see if there an easy to find peakfile for this file, and remove it. */
3448 string base = Glib::path_get_basename (*x);
3449 base += "%A"; /* this is what we add for the channel suffix of all native files,
3450 * or for the first channel of embedded files. it will miss
3451 * some peakfiles for other channels
3453 string peakpath = construct_peak_filepath (base);
3455 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3456 if (::g_unlink (peakpath.c_str ()) != 0) {
3457 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3458 g_strerror (errno)) << endmsg;
3459 /* try to back out */
3460 ::g_rename (newpath.c_str (), _path.c_str ());
3465 rep.paths.push_back (*x);
3466 rep.space += statbuf.st_size;
3469 /* dump the history list */
3473 /* save state so we don't end up a session file
3474 * referring to non-existent sources.
3481 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3487 Session::cleanup_trash_sources (CleanupReport& rep)
3489 // FIXME: needs adaptation for MIDI
3491 vector<space_and_path>::iterator i;
3497 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3499 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3501 clear_directory (dead_dir, &rep.space, &rep.paths);
3508 Session::set_dirty ()
3510 /* return early if there's nothing to do */
3515 /* never mark session dirty during loading */
3516 if (_state_of_the_state & Loading) {
3520 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3521 DirtyChanged(); /* EMIT SIGNAL */
3525 Session::set_clean ()
3527 bool was_dirty = dirty();
3529 _state_of_the_state = Clean;
3532 DirtyChanged(); /* EMIT SIGNAL */
3537 Session::set_deletion_in_progress ()
3539 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3543 Session::clear_deletion_in_progress ()
3545 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3549 Session::add_controllable (boost::shared_ptr<Controllable> c)
3551 /* this adds a controllable to the list managed by the Session.
3552 this is a subset of those managed by the Controllable class
3553 itself, and represents the only ones whose state will be saved
3554 as part of the session.
3557 Glib::Threads::Mutex::Lock lm (controllables_lock);
3558 controllables.insert (c);
3561 struct null_deleter { void operator()(void const *) const {} };
3564 Session::remove_controllable (Controllable* c)
3566 if (_state_of_the_state & Deletion) {
3570 Glib::Threads::Mutex::Lock lm (controllables_lock);
3572 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3574 if (x != controllables.end()) {
3575 controllables.erase (x);
3579 boost::shared_ptr<Controllable>
3580 Session::controllable_by_id (const PBD::ID& id)
3582 Glib::Threads::Mutex::Lock lm (controllables_lock);
3584 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3585 if ((*i)->id() == id) {
3590 return boost::shared_ptr<Controllable>();
3593 boost::shared_ptr<AutomationControl>
3594 Session::automation_control_by_id (const PBD::ID& id)
3596 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3599 boost::shared_ptr<Controllable>
3600 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3602 boost::shared_ptr<Controllable> c;
3603 boost::shared_ptr<Stripable> s;
3604 boost::shared_ptr<Route> r;
3606 switch (desc.top_level_type()) {
3607 case ControllableDescriptor::NamedRoute:
3609 std::string str = desc.top_level_name();
3611 if (str == "Master" || str == "master") {
3613 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3615 } else if (str == "auditioner") {
3618 s = route_by_name (desc.top_level_name());
3624 case ControllableDescriptor::PresentationOrderRoute:
3625 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3628 case ControllableDescriptor::PresentationOrderTrack:
3629 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3632 case ControllableDescriptor::PresentationOrderBus:
3633 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3636 case ControllableDescriptor::PresentationOrderVCA:
3637 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3640 case ControllableDescriptor::SelectionCount:
3641 s = route_by_selected_count (desc.selection_id());
3649 r = boost::dynamic_pointer_cast<Route> (s);
3651 switch (desc.subtype()) {
3652 case ControllableDescriptor::Gain:
3653 c = s->gain_control ();
3656 case ControllableDescriptor::Trim:
3657 c = s->trim_control ();
3660 case ControllableDescriptor::Solo:
3661 c = s->solo_control();
3664 case ControllableDescriptor::Mute:
3665 c = s->mute_control();
3668 case ControllableDescriptor::Recenable:
3669 c = s->rec_enable_control ();
3672 case ControllableDescriptor::PanDirection:
3673 c = s->pan_azimuth_control();
3676 case ControllableDescriptor::PanWidth:
3677 c = s->pan_width_control();
3680 case ControllableDescriptor::PanElevation:
3681 c = s->pan_elevation_control();
3684 case ControllableDescriptor::Balance:
3685 /* XXX simple pan control */
3688 case ControllableDescriptor::PluginParameter:
3690 uint32_t plugin = desc.target (0);
3691 uint32_t parameter_index = desc.target (1);
3693 /* revert to zero based counting */
3699 if (parameter_index > 0) {
3707 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3710 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3711 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3716 case ControllableDescriptor::SendGain: {
3717 uint32_t send = desc.target (0);
3724 c = r->send_level_controllable (send);
3729 /* relax and return a null pointer */
3737 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3740 Stateful::add_instant_xml (node, _path);
3743 if (write_to_config) {
3744 Config->add_instant_xml (node);
3749 Session::instant_xml (const string& node_name)
3751 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3752 if (get_disable_all_loaded_plugins ()) {
3756 return Stateful::instant_xml (node_name, _path);
3760 Session::save_history (string snapshot_name)
3768 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3769 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3773 if (snapshot_name.empty()) {
3774 snapshot_name = _current_snapshot_name;
3777 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3778 const string backup_filename = history_filename + backup_suffix;
3779 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3780 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3782 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3783 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3784 error << _("could not backup old history file, current history not saved") << endmsg;
3789 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3791 if (!tree.write (xml_path))
3793 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3795 if (g_remove (xml_path.c_str()) != 0) {
3796 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3797 xml_path, g_strerror (errno)) << endmsg;
3799 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3800 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3801 backup_path, g_strerror (errno)) << endmsg;
3811 Session::restore_history (string snapshot_name)
3815 if (snapshot_name.empty()) {
3816 snapshot_name = _current_snapshot_name;
3819 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3820 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3822 info << "Loading history from " << xml_path << endmsg;
3824 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3825 info << string_compose (_("%1: no history file \"%2\" for this session."),
3826 _name, xml_path) << endmsg;
3830 if (!tree.read (xml_path)) {
3831 error << string_compose (_("Could not understand session history file \"%1\""),
3832 xml_path) << endmsg;
3839 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3842 UndoTransaction* ut = new UndoTransaction ();
3848 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3849 !t->get_property ("tv-usec", tv_usec)) {
3853 ut->set_name (name);
3857 tv.tv_usec = tv_usec;
3858 ut->set_timestamp(tv);
3860 for (XMLNodeConstIterator child_it = t->children().begin();
3861 child_it != t->children().end(); child_it++)
3863 XMLNode *n = *child_it;
3866 if (n->name() == "MementoCommand" ||
3867 n->name() == "MementoUndoCommand" ||
3868 n->name() == "MementoRedoCommand") {
3870 if ((c = memento_command_factory(n))) {
3874 } else if (n->name() == "NoteDiffCommand") {
3875 PBD::ID id (n->property("midi-source")->value());
3876 boost::shared_ptr<MidiSource> midi_source =
3877 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3879 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3881 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3884 } else if (n->name() == "SysExDiffCommand") {
3886 PBD::ID id (n->property("midi-source")->value());
3887 boost::shared_ptr<MidiSource> midi_source =
3888 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3890 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3892 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3895 } else if (n->name() == "PatchChangeDiffCommand") {
3897 PBD::ID id (n->property("midi-source")->value());
3898 boost::shared_ptr<MidiSource> midi_source =
3899 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3901 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3903 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3906 } else if (n->name() == "StatefulDiffCommand") {
3907 if ((c = stateful_diff_command_factory (n))) {
3908 ut->add_command (c);
3911 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3922 Session::config_changed (std::string p, bool ours)
3928 if (p == "seamless-loop") {
3930 } else if (p == "rf-speed") {
3932 } else if (p == "auto-loop") {
3934 } else if (p == "session-monitoring") {
3936 } else if (p == "auto-input") {
3938 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3939 /* auto-input only makes a difference if we're rolling */
3940 set_track_monitor_input_status (!config.get_auto_input());
3943 } else if (p == "punch-in") {
3947 if ((location = _locations->auto_punch_location()) != 0) {
3949 if (config.get_punch_in ()) {
3950 replace_event (SessionEvent::PunchIn, location->start());
3952 remove_event (location->start(), SessionEvent::PunchIn);
3956 } else if (p == "punch-out") {
3960 if ((location = _locations->auto_punch_location()) != 0) {
3962 if (config.get_punch_out()) {
3963 replace_event (SessionEvent::PunchOut, location->end());
3965 clear_events (SessionEvent::PunchOut);
3969 } else if (p == "edit-mode") {
3971 Glib::Threads::Mutex::Lock lm (playlists->lock);
3973 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3974 (*i)->set_edit_mode (Config->get_edit_mode ());
3977 } else if (p == "use-video-sync") {
3979 waiting_for_sync_offset = config.get_use_video_sync();
3981 } else if (p == "mmc-control") {
3983 //poke_midi_thread ();
3985 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3987 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3989 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3991 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3993 } else if (p == "midi-control") {
3995 //poke_midi_thread ();
3997 } else if (p == "raid-path") {
3999 setup_raid_path (config.get_raid_path());
4001 } else if (p == "timecode-format") {
4005 } else if (p == "video-pullup") {
4009 } else if (p == "seamless-loop") {
4011 if (play_loop && transport_rolling()) {
4012 // to reset diskstreams etc
4013 request_play_loop (true);
4016 } else if (p == "rf-speed") {
4018 cumulative_rf_motion = 0;
4021 } else if (p == "click-sound") {
4023 setup_click_sounds (1);
4025 } else if (p == "click-emphasis-sound") {
4027 setup_click_sounds (-1);
4029 } else if (p == "clicking") {
4031 if (Config->get_clicking()) {
4032 if (_click_io && click_data) { // don't require emphasis data
4039 } else if (p == "click-record-only") {
4041 _click_rec_only = Config->get_click_record_only();
4043 } else if (p == "click-gain") {
4046 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4049 } else if (p == "send-mtc") {
4051 if (Config->get_send_mtc ()) {
4052 /* mark us ready to send */
4053 next_quarter_frame_to_send = 0;
4056 } else if (p == "send-mmc") {
4058 _mmc->enable_send (Config->get_send_mmc ());
4060 } else if (p == "jack-time-master") {
4062 engine().reset_timebase ();
4064 } else if (p == "native-file-header-format") {
4066 if (!first_file_header_format_reset) {
4067 reset_native_file_format ();
4070 first_file_header_format_reset = false;
4072 } else if (p == "native-file-data-format") {
4074 if (!first_file_data_format_reset) {
4075 reset_native_file_format ();
4078 first_file_data_format_reset = false;
4080 } else if (p == "external-sync") {
4081 if (!config.get_external_sync()) {
4082 drop_sync_source ();
4084 switch_to_sync_source (Config->get_sync_source());
4086 } else if (p == "denormal-model") {
4088 } else if (p == "history-depth") {
4089 set_history_depth (Config->get_history_depth());
4090 } else if (p == "remote-model") {
4091 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4094 } else if (p == "initial-program-change") {
4096 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4099 buf[0] = MIDI::program; // channel zero by default
4100 buf[1] = (Config->get_initial_program_change() & 0x7f);
4102 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4104 } else if (p == "solo-mute-override") {
4105 // catch_up_on_solo_mute_override ();
4106 } else if (p == "listen-position" || p == "pfl-position") {
4107 listen_position_changed ();
4108 } else if (p == "solo-control-is-listen-control") {
4109 solo_control_mode_changed ();
4110 } else if (p == "solo-mute-gain") {
4111 _solo_cut_control->Changed (true, Controllable::NoGroup);
4112 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4113 last_timecode_valid = false;
4114 } else if (p == "playback-buffer-seconds") {
4115 AudioSource::allocate_working_buffers (frame_rate());
4116 } else if (p == "ltc-source-port") {
4117 reconnect_ltc_input ();
4118 } else if (p == "ltc-sink-port") {
4119 reconnect_ltc_output ();
4120 } else if (p == "timecode-generator-offset") {
4121 ltc_tx_parse_offset();
4122 } else if (p == "auto-return-target-list") {
4123 follow_playhead_priority ();
4130 Session::set_history_depth (uint32_t d)
4132 _history.set_depth (d);
4136 Session::load_diskstreams_2X (XMLNode const & node, int)
4139 XMLNodeConstIterator citer;
4141 clist = node.children();
4143 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4146 /* diskstreams added automatically by DiskstreamCreated handler */
4147 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4148 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4149 _diskstreams_2X.push_back (dsp);
4151 error << _("Session: unknown diskstream type in XML") << endmsg;
4155 catch (failed_constructor& err) {
4156 error << _("Session: could not load diskstream via XML state") << endmsg;
4164 /** Connect things to the MMC object */
4166 Session::setup_midi_machine_control ()
4168 _mmc = new MIDI::MachineControl;
4170 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4171 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4173 if (!async_out || !async_out) {
4177 /* XXXX argh, passing raw pointers back into libmidi++ */
4179 MIDI::Port* mmc_in = async_in.get();
4180 MIDI::Port* mmc_out = async_out.get();
4182 _mmc->set_ports (mmc_in, mmc_out);
4184 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4185 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4186 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4187 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4188 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4189 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4190 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4191 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4192 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4193 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4194 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4195 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4196 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4198 /* also handle MIDI SPP because its so common */
4200 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4201 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4202 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4205 boost::shared_ptr<Controllable>
4206 Session::solo_cut_control() const
4208 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4209 * controls in Ardour that currently get presented to the user in the GUI that require
4210 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4212 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4213 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4216 return _solo_cut_control;
4220 Session::save_snapshot_name (const std::string & n)
4222 /* assure Stateful::_instant_xml is loaded
4223 * add_instant_xml() only adds to existing data and defaults
4224 * to use an empty Tree otherwise
4226 instant_xml ("LastUsedSnapshot");
4228 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4229 last_used_snapshot->set_property ("name", n);
4230 add_instant_xml (*last_used_snapshot, false);
4234 Session::set_snapshot_name (const std::string & n)
4236 _current_snapshot_name = n;
4237 save_snapshot_name (n);
4241 Session::rename (const std::string& new_name)
4243 string legal_name = legalize_for_path (new_name);
4249 string const old_sources_root = _session_dir->sources_root();
4251 if (!_writable || (_state_of_the_state & CannotSave)) {
4252 error << _("Cannot rename read-only session.") << endmsg;
4253 return 0; // don't show "messed up" warning
4255 if (record_status() == Recording) {
4256 error << _("Cannot rename session while recording") << endmsg;
4257 return 0; // don't show "messed up" warning
4260 StateProtector stp (this);
4265 * interchange subdirectory
4269 * Backup files are left unchanged and not renamed.
4272 /* Windows requires that we close all files before attempting the
4273 * rename. This works on other platforms, but isn't necessary there.
4274 * Leave it in place for all platforms though, since it may help
4275 * catch issues that could arise if the way Source files work ever
4276 * change (since most developers are not using Windows).
4279 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4280 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4286 /* pass one: not 100% safe check that the new directory names don't
4290 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4294 /* this is a stupid hack because Glib::path_get_dirname() is
4295 * lexical-only, and so passing it /a/b/c/ gives a different
4296 * result than passing it /a/b/c ...
4299 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4300 oldstr = oldstr.substr (0, oldstr.length() - 1);
4303 string base = Glib::path_get_dirname (oldstr);
4305 newstr = Glib::build_filename (base, legal_name);
4307 cerr << "Looking for " << newstr << endl;
4309 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4310 cerr << " exists\n";
4319 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4325 /* this is a stupid hack because Glib::path_get_dirname() is
4326 * lexical-only, and so passing it /a/b/c/ gives a different
4327 * result than passing it /a/b/c ...
4330 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4331 oldstr = oldstr.substr (0, oldstr.length() - 1);
4334 string base = Glib::path_get_dirname (oldstr);
4335 newstr = Glib::build_filename (base, legal_name);
4337 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4339 cerr << "Rename " << oldstr << " => " << newstr << endl;
4340 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4341 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4342 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4346 /* Reset path in "session dirs" */
4351 /* reset primary SessionDirectory object */
4354 (*_session_dir) = newstr;
4359 /* now rename directory below session_dir/interchange */
4361 string old_interchange_dir;
4362 string new_interchange_dir;
4364 /* use newstr here because we renamed the path
4365 * (folder/directory) that used to be oldstr to newstr above
4368 v.push_back (newstr);
4369 v.push_back (interchange_dir_name);
4370 v.push_back (Glib::path_get_basename (oldstr));
4372 old_interchange_dir = Glib::build_filename (v);
4375 v.push_back (newstr);
4376 v.push_back (interchange_dir_name);
4377 v.push_back (legal_name);
4379 new_interchange_dir = Glib::build_filename (v);
4381 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4383 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4384 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4385 old_interchange_dir, new_interchange_dir,
4388 error << string_compose (_("renaming %s as %2 failed (%3)"),
4389 old_interchange_dir, new_interchange_dir,
4398 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4399 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4401 cerr << "Rename " << oldstr << " => " << newstr << endl;
4403 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4404 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4405 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4411 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4413 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4414 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4416 cerr << "Rename " << oldstr << " => " << newstr << endl;
4418 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4419 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4420 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4425 /* remove old name from recent sessions */
4426 remove_recent_sessions (_path);
4429 /* update file source paths */
4431 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4432 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4434 string p = fs->path ();
4435 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4437 SourceFactory::setup_peakfile(i->second, true);
4441 set_snapshot_name (new_name);
4446 /* save state again to get everything just right */
4448 save_state (_current_snapshot_name);
4450 /* add to recent sessions */
4452 store_recent_sessions (new_name, _path);
4458 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4460 bool found_sr = false;
4461 bool found_data_format = false;
4462 program_version = "";
4464 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4468 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4472 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4475 xmlFreeParserCtxt(ctxt);
4479 xmlNodePtr node = xmlDocGetRootElement(doc);
4482 xmlFreeParserCtxt(ctxt);
4490 for (attr = node->properties; attr; attr = attr->next) {
4491 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4492 sample_rate = atoi ((char*)attr->children->content);
4497 node = node->children;
4498 while (node != NULL) {
4499 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4500 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4502 program_version = string ((const char*)val);
4503 size_t sep = program_version.find_first_of("-");
4504 if (sep != string::npos) {
4505 program_version = program_version.substr (0, sep);
4510 if (strcmp((const char*) node->name, "Config")) {
4514 for (node = node->children; node; node = node->next) {
4515 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4516 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4518 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4520 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4522 found_data_format = true;
4532 xmlFreeParserCtxt(ctxt);
4535 return !(found_sr && found_data_format); // zero if they are both found
4539 Session::get_snapshot_from_instant (const std::string& session_dir)
4541 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4543 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4548 if (!tree.read (instant_xml_path)) {
4552 XMLProperty const * prop;
4553 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4554 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4555 return prop->value();
4561 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4562 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4565 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4569 SourcePathMap source_path_map;
4571 boost::shared_ptr<AudioFileSource> afs;
4576 Glib::Threads::Mutex::Lock lm (source_lock);
4578 cerr << " total sources = " << sources.size();
4580 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4581 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4587 if (fs->within_session()) {
4591 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4592 source_path_map[fs->path()].push_back (fs);
4594 SeveralFileSources v;
4596 source_path_map.insert (make_pair (fs->path(), v));
4602 cerr << " fsources = " << total << endl;
4604 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4606 /* tell caller where we are */
4608 string old_path = i->first;
4610 callback (n, total, old_path);
4612 cerr << old_path << endl;
4616 switch (i->second.front()->type()) {
4617 case DataType::AUDIO:
4618 new_path = new_audio_source_path_for_embedded (old_path);
4621 case DataType::MIDI:
4622 /* XXX not implemented yet */
4626 if (new_path.empty()) {
4630 cerr << "Move " << old_path << " => " << new_path << endl;
4632 if (!copy_file (old_path, new_path)) {
4633 cerr << "failed !\n";
4637 /* make sure we stop looking in the external
4638 dir/folder. Remember, this is an all-or-nothing
4639 operations, it doesn't merge just some files.
4641 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4643 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4644 (*f)->set_path (new_path);
4649 save_state ("", false, false);
4655 bool accept_all_files (string const &, void *)
4661 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4663 /* 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.
4668 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4670 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4672 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4674 v.push_back (new_session_folder); /* full path */
4675 v.push_back (interchange_dir_name);
4676 v.push_back (new_session_path); /* just one directory/folder */
4677 v.push_back (typedir);
4678 v.push_back (Glib::path_get_basename (old_path));
4680 return Glib::build_filename (v);
4684 Session::save_as (SaveAs& saveas)
4686 vector<string> files;
4687 string current_folder = Glib::path_get_dirname (_path);
4688 string new_folder = legalize_for_path (saveas.new_name);
4689 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4690 int64_t total_bytes = 0;
4694 int32_t internal_file_cnt = 0;
4696 vector<string> do_not_copy_extensions;
4697 do_not_copy_extensions.push_back (statefile_suffix);
4698 do_not_copy_extensions.push_back (pending_suffix);
4699 do_not_copy_extensions.push_back (backup_suffix);
4700 do_not_copy_extensions.push_back (temp_suffix);
4701 do_not_copy_extensions.push_back (history_suffix);
4703 /* get total size */
4705 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4707 /* need to clear this because
4708 * find_files_matching_filter() is cumulative
4713 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4715 all += files.size();
4717 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4719 g_stat ((*i).c_str(), &gsb);
4720 total_bytes += gsb.st_size;
4724 /* save old values so we can switch back if we are not switching to the new session */
4726 string old_path = _path;
4727 string old_name = _name;
4728 string old_snapshot = _current_snapshot_name;
4729 string old_sd = _session_dir->root_path();
4730 vector<string> old_search_path[DataType::num_types];
4731 string old_config_search_path[DataType::num_types];
4733 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4734 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4735 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4736 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4738 /* switch session directory */
4740 (*_session_dir) = to_dir;
4742 /* create new tree */
4744 if (!_session_dir->create()) {
4745 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4750 /* copy all relevant files. Find each location in session_dirs,
4751 * and copy files from there to target.
4754 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4756 /* need to clear this because
4757 * find_files_matching_filter() is cumulative
4762 const size_t prefix_len = (*sd).path.size();
4764 /* Work just on the files within this session dir */
4766 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4768 /* add dir separator to protect against collisions with
4769 * track names (e.g. track named "audiofiles" or
4773 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4774 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4775 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4777 /* copy all the files. Handling is different for media files
4778 than others because of the *silly* subtree we have below the interchange
4779 folder. That really was a bad idea, but I'm not fixing it as part of
4780 implementing ::save_as().
4783 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4785 std::string from = *i;
4788 string filename = Glib::path_get_basename (from);
4789 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4790 if (filename == ".DS_STORE") {
4795 if (from.find (audiofile_dir_string) != string::npos) {
4797 /* audio file: only copy if asked */
4799 if (saveas.include_media && saveas.copy_media) {
4801 string to = make_new_media_path (*i, to_dir, new_folder);
4803 info << "media file copying from " << from << " to " << to << endmsg;
4805 if (!copy_file (from, to)) {
4806 throw Glib::FileError (Glib::FileError::IO_ERROR,
4807 string_compose(_("\ncopying \"%1\" failed !"), from));
4811 /* we found media files inside the session folder */
4813 internal_file_cnt++;
4815 } else if (from.find (midifile_dir_string) != string::npos) {
4817 /* midi file: always copy unless
4818 * creating an empty new session
4821 if (saveas.include_media) {
4823 string to = make_new_media_path (*i, to_dir, new_folder);
4825 info << "media file copying from " << from << " to " << to << endmsg;
4827 if (!copy_file (from, to)) {
4828 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4832 /* we found media files inside the session folder */
4834 internal_file_cnt++;
4836 } else if (from.find (analysis_dir_string) != string::npos) {
4838 /* make sure analysis dir exists in
4839 * new session folder, but we're not
4840 * copying analysis files here, see
4844 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4849 /* normal non-media file. Don't copy state, history, etc.
4852 bool do_copy = true;
4854 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4855 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4856 /* end of filename matches extension, do not copy file */
4862 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4863 /* don't copy peakfiles if
4864 * we're not copying media
4870 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4872 info << "attempting to make directory/folder " << to << endmsg;
4874 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4875 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4878 info << "attempting to copy " << from << " to " << to << endmsg;
4880 if (!copy_file (from, to)) {
4881 throw Glib::FileError (Glib::FileError::IO_ERROR,
4882 string_compose(_("\ncopying \"%1\" failed !"), from));
4887 /* measure file size even if we're not going to copy so that our Progress
4888 signals are correct, since we included these do-not-copy files
4889 in the computation of the total size and file count.
4893 g_stat (from.c_str(), &gsb);
4894 copied += gsb.st_size;
4897 double fraction = (double) copied / total_bytes;
4899 bool keep_going = true;
4901 if (saveas.copy_media) {
4903 /* no need or expectation of this if
4904 * media is not being copied, because
4905 * it will be fast(ish).
4908 /* tell someone "X percent, file M of N"; M is one-based */
4910 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4918 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4924 /* copy optional folders, if any */
4926 string old = plugins_dir ();
4927 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4928 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4929 copy_files (old, newdir);
4932 old = externals_dir ();
4933 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4934 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4935 copy_files (old, newdir);
4938 old = automation_dir ();
4939 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4940 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4941 copy_files (old, newdir);
4944 if (saveas.include_media) {
4946 if (saveas.copy_media) {
4947 #ifndef PLATFORM_WINDOWS
4948 /* There are problems with analysis files on
4949 * Windows, because they used a colon in their
4950 * names as late as 4.0. Colons are not legal
4951 * under Windows even if NTFS allows them.
4953 * This is a tricky problem to solve so for
4954 * just don't copy these files. They will be
4955 * regenerated as-needed anyway, subject to the
4956 * existing issue that the filenames will be
4957 * rejected by Windows, which is a separate
4958 * problem (though related).
4961 /* only needed if we are copying media, since the
4962 * analysis data refers to media data
4965 old = analysis_dir ();
4966 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4967 string newdir = Glib::build_filename (to_dir, "analysis");
4968 copy_files (old, newdir);
4970 #endif /* PLATFORM_WINDOWS */
4975 set_snapshot_name (saveas.new_name);
4976 _name = saveas.new_name;
4978 if (saveas.include_media && !saveas.copy_media) {
4980 /* reset search paths of the new session (which we're pretending to be right now) to
4981 include the original session search path, so we can still find all audio.
4984 if (internal_file_cnt) {
4985 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4986 ensure_search_path_includes (*s, DataType::AUDIO);
4987 cerr << "be sure to include " << *s << " for audio" << endl;
4990 /* we do not do this for MIDI because we copy
4991 all MIDI files if saveas.include_media is
4997 bool was_dirty = dirty ();
4999 save_default_options ();
5001 if (saveas.copy_media && saveas.copy_external) {
5002 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5003 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5007 saveas.final_session_folder_name = _path;
5009 store_recent_sessions (_name, _path);
5011 if (!saveas.switch_to) {
5013 /* save the new state */
5015 save_state ("", false, false, !saveas.include_media);
5017 /* switch back to the way things were */
5021 set_snapshot_name (old_snapshot);
5023 (*_session_dir) = old_sd;
5029 if (internal_file_cnt) {
5030 /* reset these to their original values */
5031 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5032 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5037 /* prune session dirs, and update disk space statistics
5042 session_dirs.clear ();
5043 session_dirs.push_back (sp);
5044 refresh_disk_space ();
5046 _writable = exists_and_writable (_path);
5048 /* ensure that all existing tracks reset their current capture source paths
5050 reset_write_sources (true, true);
5052 /* creating new write sources marks the session as
5053 dirty. If the new session is empty, then
5054 save_state() thinks we're saving a template and will
5055 not mark the session as clean. So do that here,
5056 before we save state.
5059 if (!saveas.include_media) {
5060 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5063 save_state ("", false, false, !saveas.include_media);
5065 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5066 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5069 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5070 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5076 if (fs->within_session()) {
5077 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5078 fs->set_path (newpath);
5083 } catch (Glib::FileError& e) {
5085 saveas.failure_message = e.what();
5087 /* recursively remove all the directories */
5089 remove_directory (to_dir);
5097 saveas.failure_message = _("unknown reason");
5099 /* recursively remove all the directories */
5101 remove_directory (to_dir);
5111 static void set_progress (Progress* p, size_t n, size_t t)
5113 p->set_progress (float (n) / float(t));
5117 Session::archive_session (const std::string& dest,
5118 const std::string& name,
5119 ArchiveEncode compress_audio,
5120 bool only_used_sources,
5123 if (dest.empty () || name.empty ()) {
5127 /* save current values */
5128 bool was_dirty = dirty ();
5129 string old_path = _path;
5130 string old_name = _name;
5131 string old_snapshot = _current_snapshot_name;
5132 string old_sd = _session_dir->root_path();
5133 string old_config_search_path[DataType::num_types];
5134 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5135 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5137 /* ensure that session-path is included in search-path */
5139 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5140 if ((*sd).path == old_path) {
5148 /* create temporary dir to save session to */
5149 #ifdef PLATFORM_WINDOWS
5150 char tmp[256] = "C:\\TEMP\\";
5151 GetTempPath (sizeof (tmp), tmp);
5153 char const* tmp = getenv("TMPDIR");
5158 if ((strlen (tmp) + 21) > 1024) {
5163 strcpy (tmptpl, tmp);
5164 strcat (tmptpl, "ardourarchive-XXXXXX");
5165 char* tmpdir = g_mkdtemp (tmptpl);
5171 std::string to_dir = std::string (tmpdir);
5173 /* switch session directory temporarily */
5174 (*_session_dir) = to_dir;
5176 if (!_session_dir->create()) {
5177 (*_session_dir) = old_sd;
5178 remove_directory (to_dir);
5182 /* prepare archive */
5183 string archive = Glib::build_filename (dest, name + ".tar.xz");
5185 PBD::ScopedConnectionList progress_connection;
5186 PBD::FileArchive ar (archive);
5188 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5191 /* collect files to archive */
5192 std::map<string,string> filemap;
5194 vector<string> do_not_copy_extensions;
5195 do_not_copy_extensions.push_back (statefile_suffix);
5196 do_not_copy_extensions.push_back (pending_suffix);
5197 do_not_copy_extensions.push_back (backup_suffix);
5198 do_not_copy_extensions.push_back (temp_suffix);
5199 do_not_copy_extensions.push_back (history_suffix);
5201 vector<string> blacklist_dirs;
5202 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5203 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5204 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5205 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5206 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5207 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5209 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5210 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5212 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5213 if (only_used_sources) {
5214 playlists->sync_all_regions_with_regions ();
5215 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5218 // collect audio sources for this session, calc total size for encoding
5219 // add option to only include *used* sources (see Session::cleanup_sources)
5220 size_t total_size = 0;
5222 Glib::Threads::Mutex::Lock lm (source_lock);
5223 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5224 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5225 if (!afs || afs->readable_length () == 0) {
5229 if (only_used_sources) {
5233 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5238 std::string from = afs->path();
5240 if (compress_audio != NO_ENCODE) {
5241 total_size += afs->readable_length ();
5243 if (afs->within_session()) {
5244 filemap[from] = make_new_media_path (from, name, name);
5246 filemap[from] = make_new_media_path (from, name, name);
5247 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5254 if (compress_audio != NO_ENCODE) {
5256 progress->set_progress (2); // set to "encoding"
5257 progress->set_progress (0);
5260 Glib::Threads::Mutex::Lock lm (source_lock);
5261 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5262 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5263 if (!afs || afs->readable_length () == 0) {
5267 if (only_used_sources) {
5271 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5276 orig_sources[afs] = afs->path();
5277 orig_gain[afs] = afs->gain();
5279 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5280 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5281 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5284 progress->descend ((float)afs->readable_length () / total_size);
5288 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5289 afs->replace_file (new_path);
5290 afs->set_gain (ns->gain(), true);
5293 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5297 progress->ascend ();
5303 progress->set_progress (-1); // set to "archiving"
5304 progress->set_progress (0);
5307 /* index files relevant for this session */
5308 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5309 vector<string> files;
5311 size_t prefix_len = (*sd).path.size();
5312 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5316 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5318 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5319 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5320 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5322 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5323 std::string from = *i;
5326 string filename = Glib::path_get_basename (from);
5327 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5328 if (filename == ".DS_STORE") {
5333 if (from.find (audiofile_dir_string) != string::npos) {
5335 } else if (from.find (midifile_dir_string) != string::npos) {
5336 filemap[from] = make_new_media_path (from, name, name);
5337 } else if (from.find (videofile_dir_string) != string::npos) {
5338 filemap[from] = make_new_media_path (from, name, name);
5340 bool do_copy = true;
5341 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5342 if (from.find (*v) != string::npos) {
5347 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5348 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5355 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5361 /* write session file */
5363 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5365 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5368 save_default_options ();
5370 size_t prefix_len = _path.size();
5371 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5375 /* collect session-state files */
5376 vector<string> files;
5377 do_not_copy_extensions.clear ();
5378 do_not_copy_extensions.push_back (history_suffix);
5380 blacklist_dirs.clear ();
5381 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5383 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5384 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5385 std::string from = *i;
5386 bool do_copy = true;
5387 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5388 if (from.find (*v) != string::npos) {
5393 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5394 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5400 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5404 /* restore original values */
5407 set_snapshot_name (old_snapshot);
5408 (*_session_dir) = old_sd;
5412 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5413 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5415 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5416 i->first->replace_file (i->second);
5418 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5419 i->first->set_gain (i->second, true);
5422 int rv = ar.create (filemap);
5423 remove_directory (to_dir);
5429 Session::undo (uint32_t n)
5431 if (actively_recording()) {
5439 Session::redo (uint32_t n)
5441 if (actively_recording()) {