2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/types_convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/selection.h"
118 #include "ardour/session.h"
119 #include "ardour/session_directory.h"
120 #include "ardour/session_metadata.h"
121 #include "ardour/session_playlists.h"
122 #include "ardour/session_state_utils.h"
123 #include "ardour/silentfilesource.h"
124 #include "ardour/sndfilesource.h"
125 #include "ardour/source_factory.h"
126 #include "ardour/speakers.h"
127 #include "ardour/template_utils.h"
128 #include "ardour/tempo.h"
129 #include "ardour/ticker.h"
130 #include "ardour/types_convert.h"
131 #include "ardour/user_bundle.h"
132 #include "ardour/vca.h"
133 #include "ardour/vca_manager.h"
135 #include "control_protocol/control_protocol.h"
137 #include "LuaBridge/LuaBridge.h"
139 #include "pbd/i18n.h"
143 using namespace ARDOUR;
146 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
149 Session::pre_engine_init (string fullpath)
151 if (fullpath.empty()) {
153 throw failed_constructor();
156 /* discover canonical fullpath */
158 _path = canonical_path(fullpath);
161 if (Profile->get_trx() ) {
162 // Waves TracksLive has a usecase of session replacement with a new one.
163 // We should check session state file (<session_name>.ardour) existance
164 // to determine if the session is new or not
166 string full_session_name = Glib::build_filename( fullpath, _name );
167 full_session_name += statefile_suffix;
169 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
171 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
174 /* finish initialization that can't be done in a normal C++ constructor
178 timerclear (&last_mmc_step);
179 g_atomic_int_set (&processing_prohibited, 0);
180 g_atomic_int_set (&_record_status, Disabled);
181 g_atomic_int_set (&_playback_load, 100);
182 g_atomic_int_set (&_capture_load, 100);
184 _all_route_group->set_active (true, this);
185 interpolation.add_channel_to (0, 0);
187 if (config.get_use_video_sync()) {
188 waiting_for_sync_offset = true;
190 waiting_for_sync_offset = false;
193 last_rr_session_dir = session_dirs.begin();
195 set_history_depth (Config->get_history_depth());
197 /* default: assume simple stereo speaker configuration */
199 _speakers->setup_default_speakers (2);
201 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
202 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
203 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
204 add_controllable (_solo_cut_control);
206 /* These are all static "per-class" signals */
208 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
209 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
210 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
211 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
212 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
214 /* stop IO objects from doing stuff until we're ready for them */
216 Delivery::disable_panners ();
217 IO::disable_connecting ();
221 Session::post_engine_init ()
223 BootMessage (_("Set block size and sample rate"));
225 set_block_size (_engine.samples_per_cycle());
226 set_frame_rate (_engine.sample_rate());
228 BootMessage (_("Using configuration"));
230 _midi_ports = new MidiPortManager;
232 MIDISceneChanger* msc;
234 _scene_changer = msc = new MIDISceneChanger (*this);
235 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
236 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
238 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
239 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
241 setup_midi_machine_control ();
243 if (_butler->start_thread()) {
244 error << _("Butler did not start") << endmsg;
248 if (start_midi_thread ()) {
249 error << _("MIDI I/O thread did not start") << endmsg;
253 setup_click_sounds (0);
254 setup_midi_control ();
256 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
257 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
260 /* tempo map requires sample rate knowledge */
263 _tempo_map = new TempoMap (_current_frame_rate);
264 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
265 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
267 /* MidiClock requires a tempo map */
270 midi_clock = new MidiClockTicker ();
271 midi_clock->set_session (this);
273 /* crossfades require sample rate knowledge */
275 SndFileSource::setup_standard_crossfades (*this, frame_rate());
276 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
277 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
279 AudioDiskstream::allocate_working_buffers();
280 refresh_disk_space ();
282 /* we're finally ready to call set_state() ... all objects have
283 * been created, the engine is running.
287 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
288 error << _("Could not set session state from XML") << endmsg;
292 // set_state() will call setup_raid_path(), but if it's a new session we need
293 // to call setup_raid_path() here.
294 setup_raid_path (_path);
299 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
300 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
302 Config->map_parameters (ff);
303 config.map_parameters (ft);
304 _butler->map_parameters ();
306 /* Reset all panners */
308 Delivery::reset_panners ();
310 /* this will cause the CPM to instantiate any protocols that are in use
311 * (or mandatory), which will pass it this Session, and then call
312 * set_state() on each instantiated protocol to match stored state.
315 ControlProtocolManager::instance().set_session (this);
317 /* This must be done after the ControlProtocolManager set_session above,
318 as it will set states for ports which the ControlProtocolManager creates.
321 // XXX set state of MIDI::Port's
322 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
324 /* And this must be done after the MIDI::Manager::set_port_states as
325 * it will try to make connections whose details are loaded by set_port_states.
330 /* Let control protocols know that we are now all connected, so they
331 * could start talking to surfaces if they want to.
334 ControlProtocolManager::instance().midi_connectivity_established ();
336 if (_is_new && !no_auto_connect()) {
337 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
338 auto_connect_master_bus ();
341 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
343 /* update latencies */
345 initialize_latencies ();
347 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
348 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
349 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
351 } catch (AudioEngine::PortRegistrationFailure& err) {
352 /* handle this one in a different way than all others, so that its clear what happened */
353 error << err.what() << endmsg;
355 } catch (std::exception const & e) {
356 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
359 error << _("Unknown exception during session setup") << endmsg;
363 BootMessage (_("Reset Remote Controls"));
365 // send_full_time_code (0);
366 _engine.transport_locate (0);
368 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
369 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
371 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
374 /* initial program change will be delivered later; see ::config_changed() */
376 _state_of_the_state = Clean;
378 Port::set_connecting_blocked (false);
380 DirtyChanged (); /* EMIT SIGNAL */
384 } else if (state_was_pending) {
386 remove_pending_capture_state ();
387 state_was_pending = false;
390 /* Now, finally, we can fill the playback buffers */
392 BootMessage (_("Filling playback buffers"));
394 boost::shared_ptr<RouteList> rl = routes.reader();
395 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
396 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
397 if (trk && !trk->hidden()) {
398 trk->seek (_transport_frame, true);
406 Session::session_loaded ()
410 _state_of_the_state = Clean;
412 DirtyChanged (); /* EMIT SIGNAL */
416 } else if (state_was_pending) {
418 remove_pending_capture_state ();
419 state_was_pending = false;
422 /* Now, finally, we can fill the playback buffers */
424 BootMessage (_("Filling playback buffers"));
425 force_locate (_transport_frame, false);
429 Session::raid_path () const
431 Searchpath raid_search_path;
433 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
434 raid_search_path += (*i).path;
437 return raid_search_path.to_string ();
441 Session::setup_raid_path (string path)
450 session_dirs.clear ();
452 Searchpath search_path(path);
453 Searchpath sound_search_path;
454 Searchpath midi_search_path;
456 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
458 sp.blocks = 0; // not needed
459 session_dirs.push_back (sp);
461 SessionDirectory sdir(sp.path);
463 sound_search_path += sdir.sound_path ();
464 midi_search_path += sdir.midi_path ();
467 // reset the round-robin soundfile path thingie
468 last_rr_session_dir = session_dirs.begin();
472 Session::path_is_within_session (const std::string& path)
474 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
475 if (PBD::path_is_within (i->path, path)) {
483 Session::ensure_subdirs ()
487 dir = session_directory().peak_path();
489 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
490 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
494 dir = session_directory().sound_path();
496 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
497 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
501 dir = session_directory().midi_path();
503 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
504 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
508 dir = session_directory().dead_path();
510 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
511 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
515 dir = session_directory().export_path();
517 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
518 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
522 dir = analysis_dir ();
524 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
525 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
529 dir = plugins_dir ();
531 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
532 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
536 dir = externals_dir ();
538 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
539 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
546 /** @param session_template directory containing session template, or empty.
547 * Caller must not hold process lock.
550 Session::create (const string& session_template, BusProfile* bus_profile)
552 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
553 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
557 if (ensure_subdirs ()) {
561 _writable = exists_and_writable (_path);
563 if (!session_template.empty()) {
564 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
566 FILE* in = g_fopen (in_path.c_str(), "rb");
569 /* no need to call legalize_for_path() since the string
570 * in session_template is already a legal path name
572 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
574 FILE* out = g_fopen (out_path.c_str(), "wb");
578 stringstream new_session;
581 size_t charsRead = fread (buf, sizeof(char), 1024, in);
584 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
589 if (charsRead == 0) {
592 new_session.write (buf, charsRead);
596 string file_contents = new_session.str();
597 size_t writeSize = file_contents.length();
598 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
599 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
607 if (!ARDOUR::Profile->get_trx()) {
608 /* Copy plugin state files from template to new session */
609 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
610 copy_recurse (template_plugins, plugins_dir ());
616 error << string_compose (_("Could not open %1 for writing session template"), out_path)
623 error << string_compose (_("Could not open session template %1 for reading"), in_path)
630 if (Profile->get_trx()) {
632 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
633 * Remember that this is a brand new session. Sessions
634 * loaded from saved state will get this range from the saved state.
637 set_session_range_location (0, 0);
639 /* Initial loop location, from absolute zero, length 10 seconds */
641 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
642 _locations->add (loc, true);
643 set_auto_loop_location (loc);
646 _state_of_the_state = Clean;
648 /* set up Master Out and Monitor Out if necessary */
653 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
655 // Waves Tracks: always create master bus for Tracks
656 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
657 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
665 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
666 r->input()->ensure_io (count, false, this);
667 r->output()->ensure_io (count, false, this);
673 /* prohibit auto-connect to master, because there isn't one */
674 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
678 add_routes (rl, false, false, false, PresentationInfo::max_order);
681 // Waves Tracks: Skip this. Always use autoconnection for Tracks
682 if (!ARDOUR::Profile->get_trx()) {
684 /* this allows the user to override settings with an environment variable.
687 if (no_auto_connect()) {
688 bus_profile->input_ac = AutoConnectOption (0);
689 bus_profile->output_ac = AutoConnectOption (0);
692 Config->set_input_auto_connect (bus_profile->input_ac);
693 Config->set_output_auto_connect (bus_profile->output_ac);
697 if (Config->get_use_monitor_bus() && bus_profile) {
698 add_monitor_section ();
705 Session::maybe_write_autosave()
707 if (dirty() && record_status() != Recording) {
708 save_state("", true);
713 Session::remove_pending_capture_state ()
715 std::string pending_state_file_path(_session_dir->root_path());
717 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
719 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
721 if (g_remove (pending_state_file_path.c_str()) != 0) {
722 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
723 pending_state_file_path, g_strerror (errno)) << endmsg;
727 /** Rename a state file.
728 * @param old_name Old snapshot name.
729 * @param new_name New snapshot name.
732 Session::rename_state (string old_name, string new_name)
734 if (old_name == _current_snapshot_name || old_name == _name) {
735 /* refuse to rename the current snapshot or the "main" one */
739 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
740 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
742 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
743 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
745 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
746 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
747 old_name, new_name, g_strerror(errno)) << endmsg;
751 /** Remove a state file.
752 * @param snapshot_name Snapshot name.
755 Session::remove_state (string snapshot_name)
757 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
758 // refuse to remove the current snapshot or the "main" one
762 std::string xml_path(_session_dir->root_path());
764 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
766 if (!create_backup_file (xml_path)) {
767 // don't remove it if a backup can't be made
768 // create_backup_file will log the error.
773 if (g_remove (xml_path.c_str()) != 0) {
774 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
775 xml_path, g_strerror (errno)) << endmsg;
779 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
781 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
783 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
786 std::string xml_path(_session_dir->root_path());
788 /* prevent concurrent saves from different threads */
790 Glib::Threads::Mutex::Lock lm (save_state_lock);
792 if (!_writable || (_state_of_the_state & CannotSave)) {
796 if (g_atomic_int_get(&_suspend_save)) {
800 _save_queued = false;
802 if (!_engine.connected ()) {
803 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"), PROGRAM_NAME)
809 const int64_t save_start_time = g_get_monotonic_time();
812 /* tell sources we're saving first, in case they write out to a new file
813 * which should be saved with the state rather than the old one */
814 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
816 i->second->session_saved();
817 } catch (Evoral::SMF::FileError& e) {
818 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
822 SessionSaveUnderway (); /* EMIT SIGNAL */
824 bool mark_as_clean = true;
826 if (!snapshot_name.empty() && !switch_to_snapshot) {
827 mark_as_clean = false;
831 mark_as_clean = false;
832 tree.set_root (&get_template());
834 tree.set_root (&get_state());
837 if (snapshot_name.empty()) {
838 snapshot_name = _current_snapshot_name;
839 } else if (switch_to_snapshot) {
840 set_snapshot_name (snapshot_name);
843 assert (!snapshot_name.empty());
847 /* proper save: use statefile_suffix (.ardour in English) */
849 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
851 /* make a backup copy of the old file */
853 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
854 // create_backup_file will log the error
860 /* pending save: use pending_suffix (.pending in English) */
861 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
864 std::string tmp_path(_session_dir->root_path());
865 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
867 cerr << "actually writing state to " << tmp_path << endl;
869 if (!tree.write (tmp_path)) {
870 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
871 if (g_remove (tmp_path.c_str()) != 0) {
872 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
873 tmp_path, g_strerror (errno)) << endmsg;
879 cerr << "renaming state to " << xml_path << endl;
881 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
882 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
883 tmp_path, xml_path, g_strerror(errno)) << endmsg;
884 if (g_remove (tmp_path.c_str()) != 0) {
885 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
886 tmp_path, g_strerror (errno)) << endmsg;
894 save_history (snapshot_name);
897 bool was_dirty = dirty();
899 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
902 DirtyChanged (); /* EMIT SIGNAL */
906 StateSaved (snapshot_name); /* EMIT SIGNAL */
910 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
911 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
917 Session::restore_state (string snapshot_name)
919 if (load_state (snapshot_name) == 0) {
920 set_state (*state_tree->root(), Stateful::loading_state_version);
927 Session::load_state (string snapshot_name)
932 state_was_pending = false;
934 /* check for leftover pending state from a crashed capture attempt */
936 std::string xmlpath(_session_dir->root_path());
937 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
939 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
941 /* there is pending state from a crashed capture attempt */
943 boost::optional<int> r = AskAboutPendingState();
944 if (r.get_value_or (1)) {
945 state_was_pending = true;
949 if (!state_was_pending) {
950 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
953 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
954 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
955 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
956 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
961 state_tree = new XMLTree;
965 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
967 if (!state_tree->read (xmlpath)) {
968 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
974 XMLNode const & root (*state_tree->root());
976 if (root.name() != X_("Session")) {
977 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
984 if (root.get_property ("version", version)) {
985 if (version.find ('.') != string::npos) {
986 /* old school version format */
987 if (version[0] == '2') {
988 Stateful::loading_state_version = 2000;
990 Stateful::loading_state_version = 3000;
993 Stateful::loading_state_version = string_to<int32_t>(version);
996 /* no version implies very old version of Ardour */
997 Stateful::loading_state_version = 1000;
1000 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1002 std::string backup_path(_session_dir->root_path());
1003 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1004 backup_path = Glib::build_filename (backup_path, backup_filename);
1006 // only create a backup for a given statefile version once
1008 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1010 VersionMismatch (xmlpath, backup_path);
1012 if (!copy_file (xmlpath, backup_path)) {;
1018 save_snapshot_name (snapshot_name);
1024 Session::load_options (const XMLNode& node)
1026 config.set_variables (node);
1031 Session::save_default_options ()
1033 return config.save_state();
1037 Session::get_state()
1043 Session::get_template()
1045 /* if we don't disable rec-enable, diskstreams
1046 will believe they need to store their capture
1047 sources in their state node.
1050 disable_record (false);
1052 return state(false);
1055 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1056 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1059 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1061 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1064 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1068 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1071 XMLNode* node = new XMLNode("TrackState"); // XXX
1074 PlaylistSet playlists; // SessionPlaylists
1077 // these will work with new_route_from_template()
1078 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1079 child = node->add_child ("Routes");
1080 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1081 if ((*i)->is_auditioner()) {
1084 if ((*i)->is_master() || (*i)->is_monitor()) {
1087 child->add_child_nocopy ((*i)->get_state());
1088 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1090 playlists.insert (track->playlist ());
1094 // on load, Regions in the playlists need to resolve and map Source-IDs
1095 // also playlist needs to be merged or created with new-name..
1096 // ... and Diskstream in tracks adjusted to use the correct playlist
1097 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1098 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1099 child->add_child_nocopy ((*i)->get_state ());
1100 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1101 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1102 const Region::SourceList& sl = (*s)->sources ();
1103 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1104 sources.insert (*sli);
1109 child = node->add_child ("Sources");
1110 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1111 child->add_child_nocopy ((*i)->get_state ());
1112 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1114 #ifdef PLATFORM_WINDOWS
1117 string p = fs->path ();
1118 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1122 std::string sn = Glib::build_filename (path, "share.axml");
1125 tree.set_root (node);
1126 return tree.write (sn.c_str());
1131 struct route_id_compare {
1133 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1135 return r1->id () < r2->id ();
1141 Session::state (bool full_state)
1144 XMLNode* node = new XMLNode("Session");
1147 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1149 child = node->add_child ("ProgramVersion");
1150 child->set_property("created-with", created_with);
1152 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1153 child->set_property("modified-with", modified_with);
1155 /* store configuration settings */
1159 node->set_property ("name", _name);
1160 node->set_property ("sample-rate", _base_frame_rate);
1162 if (session_dirs.size() > 1) {
1166 vector<space_and_path>::iterator i = session_dirs.begin();
1167 vector<space_and_path>::iterator next;
1169 ++i; /* skip the first one */
1173 while (i != session_dirs.end()) {
1177 if (next != session_dirs.end()) {
1178 p += G_SEARCHPATH_SEPARATOR;
1187 child = node->add_child ("Path");
1188 child->add_content (p);
1190 node->set_property ("end-is-free", _session_range_end_is_free);
1193 /* save the ID counter */
1195 node->set_property ("id-counter", ID::counter());
1197 node->set_property ("name-counter", name_id_counter ());
1199 /* save the event ID counter */
1201 node->set_property ("event-counter", Evoral::event_id_counter());
1203 /* save the VCA counter */
1205 node->set_property ("vca-counter", VCA::get_next_vca_number());
1207 /* various options */
1209 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1210 if (!midi_port_nodes.empty()) {
1211 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1212 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1213 midi_port_stuff->add_child_nocopy (**n);
1215 node->add_child_nocopy (*midi_port_stuff);
1218 XMLNode& cfgxml (config.get_variables ());
1220 /* exclude search-paths from template */
1221 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1222 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1223 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1225 node->add_child_nocopy (cfgxml);
1227 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1229 child = node->add_child ("Sources");
1232 Glib::Threads::Mutex::Lock sl (source_lock);
1234 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1236 /* Don't save information about non-file Sources, or
1237 * about non-destructive file sources that are empty
1238 * and unused by any regions.
1241 boost::shared_ptr<FileSource> fs;
1243 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1245 if (!fs->destructive()) {
1246 if (fs->empty() && !fs->used()) {
1251 child->add_child_nocopy (siter->second->get_state());
1256 child = node->add_child ("Regions");
1259 Glib::Threads::Mutex::Lock rl (region_lock);
1260 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1261 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1262 boost::shared_ptr<Region> r = i->second;
1263 /* only store regions not attached to playlists */
1264 if (r->playlist() == 0) {
1265 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1266 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1268 child->add_child_nocopy (r->get_state ());
1273 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1275 if (!cassocs.empty()) {
1276 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1278 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1279 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1280 can->set_property (X_("copy"), i->first->id());
1281 can->set_property (X_("original"), i->second->id());
1282 ca->add_child_nocopy (*can);
1289 node->add_child_nocopy (_selection->get_state());
1292 node->add_child_nocopy (_locations->get_state());
1295 Locations loc (*this);
1296 const bool was_dirty = dirty();
1297 // for a template, just create a new Locations, populate it
1298 // with the default start and end, and get the state for that.
1299 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1300 range->set (max_framepos, 0);
1302 XMLNode& locations_state = loc.get_state();
1304 if (ARDOUR::Profile->get_trx() && _locations) {
1305 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1306 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1307 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1308 locations_state.add_child_nocopy ((*i)->get_state ());
1312 node->add_child_nocopy (locations_state);
1314 /* adding a location above will have marked the session
1315 * dirty. This is an artifact, so fix it if the session wasn't
1320 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1324 child = node->add_child ("Bundles");
1326 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1327 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1328 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1330 child->add_child_nocopy (b->get_state());
1335 node->add_child_nocopy (_vca_manager->get_state());
1337 child = node->add_child ("Routes");
1339 boost::shared_ptr<RouteList> r = routes.reader ();
1341 route_id_compare cmp;
1342 RouteList xml_node_order (*r);
1343 xml_node_order.sort (cmp);
1345 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1346 if (!(*i)->is_auditioner()) {
1348 child->add_child_nocopy ((*i)->get_state());
1350 child->add_child_nocopy ((*i)->get_template());
1356 playlists->add_state (node, full_state);
1358 child = node->add_child ("RouteGroups");
1359 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1360 child->add_child_nocopy ((*i)->get_state());
1364 XMLNode* gain_child = node->add_child ("Click");
1365 gain_child->add_child_nocopy (_click_io->state (full_state));
1366 gain_child->add_child_nocopy (_click_gain->state (full_state));
1370 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1371 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1375 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1376 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1379 node->add_child_nocopy (_speakers->get_state());
1380 node->add_child_nocopy (_tempo_map->get_state());
1381 node->add_child_nocopy (get_control_protocol_state());
1384 node->add_child_copy (*_extra_xml);
1388 Glib::Threads::Mutex::Lock lm (lua_lock);
1391 luabridge::LuaRef savedstate ((*_lua_save)());
1392 saved = savedstate.cast<std::string>();
1394 lua.collect_garbage ();
1397 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1398 std::string b64s (b64);
1401 XMLNode* script_node = new XMLNode (X_("Script"));
1402 script_node->set_property (X_("lua"), LUA_VERSION);
1403 script_node->add_content (b64s);
1404 node->add_child_nocopy (*script_node);
1411 Session::get_control_protocol_state ()
1413 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1414 return cpm.get_state();
1418 Session::set_state (const XMLNode& node, int version)
1425 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1427 if (node.name() != X_("Session")) {
1428 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1432 node.get_property ("name", _name);
1434 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1436 _nominal_frame_rate = _base_frame_rate;
1438 assert (AudioEngine::instance()->running ());
1439 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1440 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1441 if (r.get_value_or (0)) {
1447 created_with = "unknown";
1448 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1449 child->get_property (X_("created-with"), created_with);
1452 setup_raid_path(_session_dir->root_path());
1454 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1457 if (node.get_property (X_("id-counter"), counter)) {
1458 ID::init_counter (counter);
1460 /* old sessions used a timebased counter, so fake
1461 * the startup ID counter based on a standard
1466 ID::init_counter (now);
1469 if (node.get_property (X_("name-counter"), counter)) {
1470 init_name_id_counter (counter);
1473 if (node.get_property (X_("event-counter"), counter)) {
1474 Evoral::init_event_id_counter (counter);
1477 if (node.get_property (X_("vca-counter"), counter)) {
1478 VCA::set_next_vca_number (counter);
1480 VCA::set_next_vca_number (1);
1483 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1484 _midi_ports->set_midi_port_states (child->children());
1487 IO::disable_connecting ();
1489 Stateful::save_extra_xml (node);
1491 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1492 load_options (*child);
1493 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1494 load_options (*child);
1496 error << _("Session: XML state has no options section") << endmsg;
1499 if (version >= 3000) {
1500 if ((child = find_named_node (node, "Metadata")) == 0) {
1501 warning << _("Session: XML state has no metadata section") << endmsg;
1502 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1507 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1508 _speakers->set_state (*child, version);
1511 if ((child = find_named_node (node, "Sources")) == 0) {
1512 error << _("Session: XML state has no sources section") << endmsg;
1514 } else if (load_sources (*child)) {
1518 if ((child = find_named_node (node, "TempoMap")) == 0) {
1519 error << _("Session: XML state has no Tempo Map section") << endmsg;
1521 } else if (_tempo_map->set_state (*child, version)) {
1525 if ((child = find_named_node (node, "Locations")) == 0) {
1526 error << _("Session: XML state has no locations section") << endmsg;
1528 } else if (_locations->set_state (*child, version)) {
1532 locations_changed ();
1534 if (_session_range_location) {
1535 AudioFileSource::set_header_position_offset (_session_range_location->start());
1538 if ((child = find_named_node (node, "Regions")) == 0) {
1539 error << _("Session: XML state has no Regions section") << endmsg;
1541 } else if (load_regions (*child)) {
1545 if ((child = find_named_node (node, "Playlists")) == 0) {
1546 error << _("Session: XML state has no playlists section") << endmsg;
1548 } else if (playlists->load (*this, *child)) {
1552 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1554 } else if (playlists->load_unused (*this, *child)) {
1558 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1559 if (load_compounds (*child)) {
1564 if (version >= 3000) {
1565 if ((child = find_named_node (node, "Bundles")) == 0) {
1566 warning << _("Session: XML state has no bundles section") << endmsg;
1569 /* We can't load Bundles yet as they need to be able
1570 * to convert from port names to Port objects, which can't happen until
1572 _bundle_xml_node = new XMLNode (*child);
1576 if (version < 3000) {
1577 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1578 error << _("Session: XML state has no diskstreams section") << endmsg;
1580 } else if (load_diskstreams_2X (*child, version)) {
1585 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1586 _vca_manager->set_state (*child, version);
1589 if ((child = find_named_node (node, "Routes")) == 0) {
1590 error << _("Session: XML state has no routes section") << endmsg;
1592 } else if (load_routes (*child, version)) {
1596 /* Now that we have Routes and masters loaded, connect them if appropriate */
1598 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1600 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1601 _diskstreams_2X.clear ();
1603 if (version >= 3000) {
1605 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1606 error << _("Session: XML state has no route groups section") << endmsg;
1608 } else if (load_route_groups (*child, version)) {
1612 } else if (version < 3000) {
1614 if ((child = find_named_node (node, "EditGroups")) == 0) {
1615 error << _("Session: XML state has no edit groups section") << endmsg;
1617 } else if (load_route_groups (*child, version)) {
1621 if ((child = find_named_node (node, "MixGroups")) == 0) {
1622 error << _("Session: XML state has no mix groups section") << endmsg;
1624 } else if (load_route_groups (*child, version)) {
1629 if ((child = find_named_node (node, "Click")) == 0) {
1630 warning << _("Session: XML state has no click section") << endmsg;
1631 } else if (_click_io) {
1632 setup_click_state (&node);
1635 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1636 ControlProtocolManager::instance().set_state (*child, version);
1639 if ((child = find_named_node (node, "Script"))) {
1640 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1641 if (!(*n)->is_content ()) { continue; }
1643 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1645 Glib::Threads::Mutex::Lock lm (lua_lock);
1646 (*_lua_load)(std::string ((const char*)buf, size));
1647 } catch (luabridge::LuaException const& e) {
1648 cerr << "LuaException:" << e.what () << endl;
1654 if ((child = find_named_node (node, X_("Selection")))) {
1655 _selection->set_state (*child, version);
1658 update_route_record_state ();
1660 /* here beginneth the second phase ... */
1661 set_snapshot_name (_current_snapshot_name);
1663 StateReady (); /* EMIT SIGNAL */
1676 Session::load_routes (const XMLNode& node, int version)
1679 XMLNodeConstIterator niter;
1680 RouteList new_routes;
1682 nlist = node.children();
1686 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1688 boost::shared_ptr<Route> route;
1689 if (version < 3000) {
1690 route = XMLRouteFactory_2X (**niter, version);
1692 route = XMLRouteFactory (**niter, version);
1696 error << _("Session: cannot create Route from XML description.") << endmsg;
1700 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1702 new_routes.push_back (route);
1705 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1707 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1709 BootMessage (_("Finished adding tracks/busses"));
1714 boost::shared_ptr<Route>
1715 Session::XMLRouteFactory (const XMLNode& node, int version)
1717 boost::shared_ptr<Route> ret;
1719 if (node.name() != "Route") {
1723 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1725 DataType type = DataType::AUDIO;
1726 node.get_property("default-type", type);
1728 assert (type != DataType::NIL);
1732 boost::shared_ptr<Track> track;
1734 if (type == DataType::AUDIO) {
1735 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1737 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1740 if (track->init()) {
1744 if (track->set_state (node, version)) {
1748 BOOST_MARK_TRACK (track);
1752 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1753 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1755 if (r->init () == 0 && r->set_state (node, version) == 0) {
1756 BOOST_MARK_ROUTE (r);
1764 boost::shared_ptr<Route>
1765 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1767 boost::shared_ptr<Route> ret;
1769 if (node.name() != "Route") {
1773 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1775 ds_prop = node.property (X_("diskstream"));
1778 DataType type = DataType::AUDIO;
1779 node.get_property("default-type", type);
1781 assert (type != DataType::NIL);
1785 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1786 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1790 if (i == _diskstreams_2X.end()) {
1791 error << _("Could not find diskstream for route") << endmsg;
1792 return boost::shared_ptr<Route> ();
1795 boost::shared_ptr<Track> track;
1797 if (type == DataType::AUDIO) {
1798 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1800 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1803 if (track->init()) {
1807 if (track->set_state (node, version)) {
1811 track->set_diskstream (*i);
1813 BOOST_MARK_TRACK (track);
1817 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1818 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1820 if (r->init () == 0 && r->set_state (node, version) == 0) {
1821 BOOST_MARK_ROUTE (r);
1830 Session::load_regions (const XMLNode& node)
1833 XMLNodeConstIterator niter;
1834 boost::shared_ptr<Region> region;
1836 nlist = node.children();
1840 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1841 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1842 error << _("Session: cannot create Region from XML description.");
1843 XMLProperty const * name = (**niter).property("name");
1846 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1857 Session::load_compounds (const XMLNode& node)
1859 XMLNodeList calist = node.children();
1860 XMLNodeConstIterator caiter;
1861 XMLProperty const * caprop;
1863 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1864 XMLNode* ca = *caiter;
1868 if ((caprop = ca->property (X_("original"))) == 0) {
1871 orig_id = caprop->value();
1873 if ((caprop = ca->property (X_("copy"))) == 0) {
1876 copy_id = caprop->value();
1878 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1879 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1881 if (!orig || !copy) {
1882 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1888 RegionFactory::add_compound_association (orig, copy);
1895 Session::load_nested_sources (const XMLNode& node)
1898 XMLNodeConstIterator niter;
1900 nlist = node.children();
1902 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1903 if ((*niter)->name() == "Source") {
1905 /* it may already exist, so don't recreate it unnecessarily
1908 XMLProperty const * prop = (*niter)->property (X_("id"));
1910 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1914 ID source_id (prop->value());
1916 if (!source_by_id (source_id)) {
1919 SourceFactory::create (*this, **niter, true);
1921 catch (failed_constructor& err) {
1922 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1929 boost::shared_ptr<Region>
1930 Session::XMLRegionFactory (const XMLNode& node, bool full)
1932 XMLProperty const * type = node.property("type");
1936 const XMLNodeList& nlist = node.children();
1938 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1939 XMLNode *child = (*niter);
1940 if (child->name() == "NestedSource") {
1941 load_nested_sources (*child);
1945 if (!type || type->value() == "audio") {
1946 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1947 } else if (type->value() == "midi") {
1948 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1951 } catch (failed_constructor& err) {
1952 return boost::shared_ptr<Region> ();
1955 return boost::shared_ptr<Region> ();
1958 boost::shared_ptr<AudioRegion>
1959 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1961 XMLProperty const * prop;
1962 boost::shared_ptr<Source> source;
1963 boost::shared_ptr<AudioSource> as;
1965 SourceList master_sources;
1966 uint32_t nchans = 1;
1969 if (node.name() != X_("Region")) {
1970 return boost::shared_ptr<AudioRegion>();
1973 node.get_property (X_("channels"), nchans);
1975 if ((prop = node.property ("name")) == 0) {
1976 cerr << "no name for this region\n";
1980 if ((prop = node.property (X_("source-0"))) == 0) {
1981 if ((prop = node.property ("source")) == 0) {
1982 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1983 return boost::shared_ptr<AudioRegion>();
1987 PBD::ID s_id (prop->value());
1989 if ((source = source_by_id (s_id)) == 0) {
1990 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1991 return boost::shared_ptr<AudioRegion>();
1994 as = boost::dynamic_pointer_cast<AudioSource>(source);
1996 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1997 return boost::shared_ptr<AudioRegion>();
2000 sources.push_back (as);
2002 /* pickup other channels */
2004 for (uint32_t n=1; n < nchans; ++n) {
2005 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2006 if ((prop = node.property (buf)) != 0) {
2008 PBD::ID id2 (prop->value());
2010 if ((source = source_by_id (id2)) == 0) {
2011 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2012 return boost::shared_ptr<AudioRegion>();
2015 as = boost::dynamic_pointer_cast<AudioSource>(source);
2017 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2018 return boost::shared_ptr<AudioRegion>();
2020 sources.push_back (as);
2024 for (uint32_t n = 0; n < nchans; ++n) {
2025 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2026 if ((prop = node.property (buf)) != 0) {
2028 PBD::ID id2 (prop->value());
2030 if ((source = source_by_id (id2)) == 0) {
2031 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2032 return boost::shared_ptr<AudioRegion>();
2035 as = boost::dynamic_pointer_cast<AudioSource>(source);
2037 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2038 return boost::shared_ptr<AudioRegion>();
2040 master_sources.push_back (as);
2045 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2047 /* a final detail: this is the one and only place that we know how long missing files are */
2049 if (region->whole_file()) {
2050 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2051 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2053 sfp->set_length (region->length());
2058 if (!master_sources.empty()) {
2059 if (master_sources.size() != nchans) {
2060 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2062 region->set_master_sources (master_sources);
2070 catch (failed_constructor& err) {
2071 return boost::shared_ptr<AudioRegion>();
2075 boost::shared_ptr<MidiRegion>
2076 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2078 XMLProperty const * prop;
2079 boost::shared_ptr<Source> source;
2080 boost::shared_ptr<MidiSource> ms;
2083 if (node.name() != X_("Region")) {
2084 return boost::shared_ptr<MidiRegion>();
2087 if ((prop = node.property ("name")) == 0) {
2088 cerr << "no name for this region\n";
2092 if ((prop = node.property (X_("source-0"))) == 0) {
2093 if ((prop = node.property ("source")) == 0) {
2094 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2095 return boost::shared_ptr<MidiRegion>();
2099 PBD::ID s_id (prop->value());
2101 if ((source = source_by_id (s_id)) == 0) {
2102 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2103 return boost::shared_ptr<MidiRegion>();
2106 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2108 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2109 return boost::shared_ptr<MidiRegion>();
2112 sources.push_back (ms);
2115 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2116 /* a final detail: this is the one and only place that we know how long missing files are */
2118 if (region->whole_file()) {
2119 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2120 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2122 sfp->set_length (region->length());
2130 catch (failed_constructor& err) {
2131 return boost::shared_ptr<MidiRegion>();
2136 Session::get_sources_as_xml ()
2139 XMLNode* node = new XMLNode (X_("Sources"));
2140 Glib::Threads::Mutex::Lock lm (source_lock);
2142 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2143 node->add_child_nocopy (i->second->get_state());
2150 Session::reset_write_sources (bool mark_write_complete, bool force)
2152 boost::shared_ptr<RouteList> rl = routes.reader();
2153 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2154 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2156 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2157 tr->reset_write_sources(mark_write_complete, force);
2158 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2164 Session::load_sources (const XMLNode& node)
2167 XMLNodeConstIterator niter;
2168 /* don't need this but it stops some
2169 * versions of gcc complaining about
2170 * discarded return values.
2172 boost::shared_ptr<Source> source;
2174 nlist = node.children();
2177 std::map<std::string, std::string> relocation;
2179 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2180 #ifdef PLATFORM_WINDOWS
2184 XMLNode srcnode (**niter);
2185 bool try_replace_abspath = true;
2189 #ifdef PLATFORM_WINDOWS
2190 // do not show "insert media" popups (files embedded from removable media).
2191 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2193 if ((source = XMLSourceFactory (srcnode)) == 0) {
2194 error << _("Session: cannot create Source from XML description.") << endmsg;
2196 #ifdef PLATFORM_WINDOWS
2197 SetErrorMode(old_mode);
2200 } catch (MissingSource& err) {
2201 #ifdef PLATFORM_WINDOWS
2202 SetErrorMode(old_mode);
2205 /* try previous abs path replacements first */
2206 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2207 std::string dir = Glib::path_get_dirname (err.path);
2208 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2209 if (rl != relocation.end ()) {
2210 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2211 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2212 srcnode.set_property ("origin", newpath);
2213 try_replace_abspath = false;
2220 _missing_file_replacement = "";
2222 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2223 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2224 PROGRAM_NAME) << endmsg;
2228 if (!no_questions_about_missing_files) {
2229 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2234 switch (user_choice) {
2236 /* user added a new search location
2237 * or selected a new absolute path,
2239 if (Glib::path_is_absolute (err.path)) {
2240 if (!_missing_file_replacement.empty ()) {
2241 /* replace origin, in XML */
2242 std::string newpath = Glib::build_filename (
2243 _missing_file_replacement, Glib::path_get_basename (err.path));
2244 srcnode.set_property ("origin", newpath);
2245 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2246 _missing_file_replacement = "";
2253 /* user asked to quit the entire session load */
2257 no_questions_about_missing_files = true;
2261 no_questions_about_missing_files = true;
2268 case DataType::AUDIO:
2269 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2272 case DataType::MIDI:
2273 /* The MIDI file is actually missing so
2274 * just create a new one in the same
2275 * location. Do not announce its
2279 if (!Glib::path_is_absolute (err.path)) {
2280 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2282 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2287 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2288 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2289 /* reset ID to match the missing one */
2290 source->set_id (**niter);
2291 /* Now we can announce it */
2292 SourceFactory::SourceCreated (source);
2303 boost::shared_ptr<Source>
2304 Session::XMLSourceFactory (const XMLNode& node)
2306 if (node.name() != "Source") {
2307 return boost::shared_ptr<Source>();
2311 /* note: do peak building in another thread when loading session state */
2312 return SourceFactory::create (*this, node, true);
2315 catch (failed_constructor& err) {
2316 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2317 return boost::shared_ptr<Source>();
2322 Session::save_template (string template_name, bool replace_existing)
2324 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2328 bool absolute_path = Glib::path_is_absolute (template_name);
2330 /* directory to put the template in */
2331 std::string template_dir_path;
2333 if (!absolute_path) {
2334 std::string user_template_dir(user_template_directory());
2336 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2337 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2338 user_template_dir, g_strerror (errno)) << endmsg;
2342 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2344 template_dir_path = template_name;
2347 if (!ARDOUR::Profile->get_trx()) {
2348 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2349 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2350 template_dir_path) << endmsg;
2354 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2355 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2356 template_dir_path, g_strerror (errno)) << endmsg;
2362 std::string template_file_path;
2364 if (ARDOUR::Profile->get_trx()) {
2365 template_file_path = template_name;
2367 if (absolute_path) {
2368 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2370 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2374 SessionSaveUnderway (); /* EMIT SIGNAL */
2379 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2380 tree.set_root (&get_template());
2383 if (!tree.write (template_file_path)) {
2384 error << _("template not saved") << endmsg;
2388 store_recent_templates (template_file_path);
2394 Session::refresh_disk_space ()
2396 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2398 Glib::Threads::Mutex::Lock lm (space_lock);
2400 /* get freespace on every FS that is part of the session path */
2402 _total_free_4k_blocks = 0;
2403 _total_free_4k_blocks_uncertain = false;
2405 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2406 #if defined(__NetBSD__)
2407 struct statvfs statfsbuf;
2409 statvfs (i->path.c_str(), &statfsbuf);
2411 struct statfs statfsbuf;
2413 statfs (i->path.c_str(), &statfsbuf);
2415 double const scale = statfsbuf.f_bsize / 4096.0;
2417 /* See if this filesystem is read-only */
2418 struct statvfs statvfsbuf;
2419 statvfs (i->path.c_str(), &statvfsbuf);
2421 /* f_bavail can be 0 if it is undefined for whatever
2422 filesystem we are looking at; Samba shares mounted
2423 via GVFS are an example of this.
2425 if (statfsbuf.f_bavail == 0) {
2426 /* block count unknown */
2428 i->blocks_unknown = true;
2429 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2430 /* read-only filesystem */
2432 i->blocks_unknown = false;
2434 /* read/write filesystem with known space */
2435 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2436 i->blocks_unknown = false;
2439 _total_free_4k_blocks += i->blocks;
2440 if (i->blocks_unknown) {
2441 _total_free_4k_blocks_uncertain = true;
2444 #elif defined PLATFORM_WINDOWS
2445 vector<string> scanned_volumes;
2446 vector<string>::iterator j;
2447 vector<space_and_path>::iterator i;
2448 DWORD nSectorsPerCluster, nBytesPerSector,
2449 nFreeClusters, nTotalClusters;
2453 _total_free_4k_blocks = 0;
2455 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2456 strncpy (disk_drive, (*i).path.c_str(), 3);
2460 volume_found = false;
2461 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2463 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2464 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2465 i->blocks = (uint32_t)(nFreeBytes / 4096);
2467 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2468 if (0 == j->compare(disk_drive)) {
2469 volume_found = true;
2474 if (!volume_found) {
2475 scanned_volumes.push_back(disk_drive);
2476 _total_free_4k_blocks += i->blocks;
2481 if (0 == _total_free_4k_blocks) {
2482 strncpy (disk_drive, path().c_str(), 3);
2485 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2487 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2488 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2489 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2496 Session::get_best_session_directory_for_new_audio ()
2498 vector<space_and_path>::iterator i;
2499 string result = _session_dir->root_path();
2501 /* handle common case without system calls */
2503 if (session_dirs.size() == 1) {
2507 /* OK, here's the algorithm we're following here:
2509 We want to select which directory to use for
2510 the next file source to be created. Ideally,
2511 we'd like to use a round-robin process so as to
2512 get maximum performance benefits from splitting
2513 the files across multiple disks.
2515 However, in situations without much diskspace, an
2516 RR approach may end up filling up a filesystem
2517 with new files while others still have space.
2518 Its therefore important to pay some attention to
2519 the freespace in the filesystem holding each
2520 directory as well. However, if we did that by
2521 itself, we'd keep creating new files in the file
2522 system with the most space until it was as full
2523 as all others, thus negating any performance
2524 benefits of this RAID-1 like approach.
2526 So, we use a user-configurable space threshold. If
2527 there are at least 2 filesystems with more than this
2528 much space available, we use RR selection between them.
2529 If not, then we pick the filesystem with the most space.
2531 This gets a good balance between the two
2535 refresh_disk_space ();
2537 int free_enough = 0;
2539 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2540 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2545 if (free_enough >= 2) {
2546 /* use RR selection process, ensuring that the one
2550 i = last_rr_session_dir;
2553 if (++i == session_dirs.end()) {
2554 i = session_dirs.begin();
2557 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2558 SessionDirectory sdir(i->path);
2559 if (sdir.create ()) {
2561 last_rr_session_dir = i;
2566 } while (i != last_rr_session_dir);
2570 /* pick FS with the most freespace (and that
2571 seems to actually work ...)
2574 vector<space_and_path> sorted;
2575 space_and_path_ascending_cmp cmp;
2577 sorted = session_dirs;
2578 sort (sorted.begin(), sorted.end(), cmp);
2580 for (i = sorted.begin(); i != sorted.end(); ++i) {
2581 SessionDirectory sdir(i->path);
2582 if (sdir.create ()) {
2584 last_rr_session_dir = i;
2594 Session::automation_dir () const
2596 return Glib::build_filename (_path, automation_dir_name);
2600 Session::analysis_dir () const
2602 return Glib::build_filename (_path, analysis_dir_name);
2606 Session::plugins_dir () const
2608 return Glib::build_filename (_path, plugins_dir_name);
2612 Session::externals_dir () const
2614 return Glib::build_filename (_path, externals_dir_name);
2618 Session::load_bundles (XMLNode const & node)
2620 XMLNodeList nlist = node.children();
2621 XMLNodeConstIterator niter;
2625 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2626 if ((*niter)->name() == "InputBundle") {
2627 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2628 } else if ((*niter)->name() == "OutputBundle") {
2629 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2631 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2640 Session::load_route_groups (const XMLNode& node, int version)
2642 XMLNodeList nlist = node.children();
2643 XMLNodeConstIterator niter;
2647 if (version >= 3000) {
2649 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2650 if ((*niter)->name() == "RouteGroup") {
2651 RouteGroup* rg = new RouteGroup (*this, "");
2652 add_route_group (rg);
2653 rg->set_state (**niter, version);
2657 } else if (version < 3000) {
2659 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2660 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2661 RouteGroup* rg = new RouteGroup (*this, "");
2662 add_route_group (rg);
2663 rg->set_state (**niter, version);
2672 state_file_filter (const string &str, void* /*arg*/)
2674 return (str.length() > strlen(statefile_suffix) &&
2675 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2679 remove_end(string state)
2681 string statename(state);
2683 string::size_type start,end;
2684 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2685 statename = statename.substr (start+1);
2688 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2689 end = statename.length();
2692 return string(statename.substr (0, end));
2696 Session::possible_states (string path)
2698 vector<string> states;
2699 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2701 transform(states.begin(), states.end(), states.begin(), remove_end);
2703 sort (states.begin(), states.end());
2709 Session::possible_states () const
2711 return possible_states(_path);
2715 Session::new_route_group (const std::string& name)
2717 RouteGroup* rg = NULL;
2719 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2720 if ((*i)->name () == name) {
2727 rg = new RouteGroup (*this, name);
2728 add_route_group (rg);
2734 Session::add_route_group (RouteGroup* g)
2736 _route_groups.push_back (g);
2737 route_group_added (g); /* EMIT SIGNAL */
2739 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2740 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2741 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2747 Session::remove_route_group (RouteGroup& rg)
2749 list<RouteGroup*>::iterator i;
2751 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2752 _route_groups.erase (i);
2755 route_group_removed (); /* EMIT SIGNAL */
2759 /** Set a new order for our route groups, without adding or removing any.
2760 * @param groups Route group list in the new order.
2763 Session::reorder_route_groups (list<RouteGroup*> groups)
2765 _route_groups = groups;
2767 route_groups_reordered (); /* EMIT SIGNAL */
2773 Session::route_group_by_name (string name)
2775 list<RouteGroup *>::iterator i;
2777 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2778 if ((*i)->name() == name) {
2786 Session::all_route_group() const
2788 return *_all_route_group;
2792 Session::add_commands (vector<Command*> const & cmds)
2794 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2800 Session::add_command (Command* const cmd)
2802 assert (_current_trans);
2803 DEBUG_UNDO_HISTORY (
2804 string_compose ("Current Undo Transaction %1, adding command: %2",
2805 _current_trans->name (),
2807 _current_trans->add_command (cmd);
2810 PBD::StatefulDiffCommand*
2811 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2813 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2819 Session::begin_reversible_command (const string& name)
2821 begin_reversible_command (g_quark_from_string (name.c_str ()));
2824 /** Begin a reversible command using a GQuark to identify it.
2825 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2826 * but there must be as many begin...()s as there are commit...()s.
2829 Session::begin_reversible_command (GQuark q)
2831 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2832 to hold all the commands that are committed. This keeps the order of
2833 commands correct in the history.
2836 if (_current_trans == 0) {
2837 DEBUG_UNDO_HISTORY (string_compose (
2838 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2840 /* start a new transaction */
2841 assert (_current_trans_quarks.empty ());
2842 _current_trans = new UndoTransaction();
2843 _current_trans->set_name (g_quark_to_string (q));
2845 DEBUG_UNDO_HISTORY (
2846 string_compose ("Begin Reversible Command, current transaction: %1",
2847 _current_trans->name ()));
2850 _current_trans_quarks.push_front (q);
2854 Session::abort_reversible_command ()
2856 if (_current_trans != 0) {
2857 DEBUG_UNDO_HISTORY (
2858 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2859 _current_trans->clear();
2860 delete _current_trans;
2862 _current_trans_quarks.clear();
2867 Session::commit_reversible_command (Command *cmd)
2869 assert (_current_trans);
2870 assert (!_current_trans_quarks.empty ());
2875 DEBUG_UNDO_HISTORY (
2876 string_compose ("Current Undo Transaction %1, adding command: %2",
2877 _current_trans->name (),
2879 _current_trans->add_command (cmd);
2882 DEBUG_UNDO_HISTORY (
2883 string_compose ("Commit Reversible Command, current transaction: %1",
2884 _current_trans->name ()));
2886 _current_trans_quarks.pop_front ();
2888 if (!_current_trans_quarks.empty ()) {
2889 DEBUG_UNDO_HISTORY (
2890 string_compose ("Commit Reversible Command, transaction is not "
2891 "top-level, current transaction: %1",
2892 _current_trans->name ()));
2893 /* the transaction we're committing is not the top-level one */
2897 if (_current_trans->empty()) {
2898 /* no commands were added to the transaction, so just get rid of it */
2899 DEBUG_UNDO_HISTORY (
2900 string_compose ("Commit Reversible Command, No commands were "
2901 "added to current transaction: %1",
2902 _current_trans->name ()));
2903 delete _current_trans;
2908 gettimeofday (&now, 0);
2909 _current_trans->set_timestamp (now);
2911 _history.add (_current_trans);
2916 accept_all_audio_files (const string& path, void* /*arg*/)
2918 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2922 if (!AudioFileSource::safe_audio_file_extension (path)) {
2930 accept_all_midi_files (const string& path, void* /*arg*/)
2932 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2936 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
2937 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
2938 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2942 accept_all_state_files (const string& path, void* /*arg*/)
2944 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2948 std::string const statefile_ext (statefile_suffix);
2949 if (path.length() >= statefile_ext.length()) {
2950 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2957 Session::find_all_sources (string path, set<string>& result)
2962 if (!tree.read (path)) {
2966 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2971 XMLNodeConstIterator niter;
2973 nlist = node->children();
2977 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2979 XMLProperty const * prop;
2981 if ((prop = (*niter)->property (X_("type"))) == 0) {
2985 DataType type (prop->value());
2987 if ((prop = (*niter)->property (X_("name"))) == 0) {
2991 if (Glib::path_is_absolute (prop->value())) {
2992 /* external file, ignore */
3000 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3001 result.insert (found_path);
3009 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3011 vector<string> state_files;
3013 string this_snapshot_path;
3019 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3020 ripped = ripped.substr (0, ripped.length() - 1);
3023 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3025 if (state_files.empty()) {
3030 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3031 this_snapshot_path += statefile_suffix;
3033 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3035 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3037 if (exclude_this_snapshot && *i == this_snapshot_path) {
3038 cerr << "\texcluded\n";
3043 if (find_all_sources (*i, result) < 0) {
3051 struct RegionCounter {
3052 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3053 AudioSourceList::iterator iter;
3054 boost::shared_ptr<Region> region;
3057 RegionCounter() : count (0) {}
3061 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3063 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3064 return r.get_value_or (1);
3068 Session::cleanup_regions ()
3070 bool removed = false;
3071 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3073 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3075 uint32_t used = playlists->region_use_count (i->second);
3077 if (used == 0 && !i->second->automatic ()) {
3078 boost::weak_ptr<Region> w = i->second;
3081 RegionFactory::map_remove (w);
3088 // re-check to remove parent references of compound regions
3089 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3090 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3094 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3095 if (0 == playlists->region_use_count (i->second)) {
3096 boost::weak_ptr<Region> w = i->second;
3098 RegionFactory::map_remove (w);
3105 /* dump the history list */
3112 Session::can_cleanup_peakfiles () const
3114 if (deletion_in_progress()) {
3117 if (!_writable || (_state_of_the_state & CannotSave)) {
3118 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3121 if (record_status() == Recording) {
3122 error << _("Cannot cleanup peak-files while recording") << endmsg;
3129 Session::cleanup_peakfiles ()
3131 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3136 assert (can_cleanup_peakfiles ());
3137 assert (!peaks_cleanup_in_progres());
3139 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3141 int timeout = 5000; // 5 seconds
3142 while (!SourceFactory::files_with_peaks.empty()) {
3143 Glib::usleep (1000);
3144 if (--timeout < 0) {
3145 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3146 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3151 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3152 boost::shared_ptr<AudioSource> as;
3153 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3154 as->close_peakfile();
3158 PBD::clear_directory (session_directory().peak_path());
3160 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3162 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3163 boost::shared_ptr<AudioSource> as;
3164 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3165 SourceFactory::setup_peakfile(as, true);
3172 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3174 pl->deep_sources (*all_sources);
3178 Session::cleanup_sources (CleanupReport& rep)
3180 // FIXME: needs adaptation to midi
3182 vector<boost::shared_ptr<Source> > dead_sources;
3185 vector<string> candidates;
3186 vector<string> unused;
3187 set<string> sources_used_by_all_snapshots;
3194 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3196 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3198 /* this is mostly for windows which doesn't allow file
3199 * renaming if the file is in use. But we don't special
3200 * case it because we need to know if this causes
3201 * problems, and the easiest way to notice that is to
3202 * keep it in place for all platforms.
3205 request_stop (false);
3207 _butler->wait_until_finished ();
3209 /* consider deleting all unused playlists */
3211 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3216 /* sync the "all regions" property of each playlist with its current state */
3218 playlists->sync_all_regions_with_regions ();
3220 /* find all un-used sources */
3225 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3227 SourceMap::iterator tmp;
3232 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3236 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3237 dead_sources.push_back (i->second);
3238 i->second->drop_references ();
3244 /* build a list of all the possible audio directories for the session */
3246 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3247 SessionDirectory sdir ((*i).path);
3248 asp += sdir.sound_path();
3250 audio_path += asp.to_string();
3253 /* build a list of all the possible midi directories for the session */
3255 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3256 SessionDirectory sdir ((*i).path);
3257 msp += sdir.midi_path();
3259 midi_path += msp.to_string();
3261 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3262 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3264 /* add sources from all other snapshots as "used", but don't use this
3265 snapshot because the state file on disk still references sources we
3266 may have already dropped.
3269 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3271 /* Although the region factory has a list of all regions ever created
3272 * for this session, we're only interested in regions actually in
3273 * playlists right now. So merge all playlist regions lists together.
3275 * This will include the playlists used within compound regions.
3278 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3280 /* add our current source list
3283 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3284 boost::shared_ptr<FileSource> fs;
3285 SourceMap::iterator tmp = i;
3288 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3294 /* this is mostly for windows which doesn't allow file
3295 * renaming if the file is in use. But we do not special
3296 * case it because we need to know if this causes
3297 * problems, and the easiest way to notice that is to
3298 * keep it in place for all platforms.
3303 if (!fs->is_stub()) {
3305 /* Note that we're checking a list of all
3306 * sources across all snapshots with the list
3307 * of sources used by this snapshot.
3310 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3311 /* this source is in use by this snapshot */
3312 sources_used_by_all_snapshots.insert (fs->path());
3313 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3315 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3316 /* this source is NOT in use by this snapshot */
3318 /* remove all related regions from RegionFactory master list */
3320 RegionFactory::remove_regions_using_source (i->second);
3322 /* remove from our current source list
3323 * also. We may not remove it from
3324 * disk, because it may be used by
3325 * other snapshots, but it isn't used inside this
3326 * snapshot anymore, so we don't need a
3337 /* now check each candidate source to see if it exists in the list of
3338 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3341 cerr << "Candidates: " << candidates.size() << endl;
3342 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3344 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3349 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3351 tmppath1 = canonical_path (spath);
3352 tmppath2 = canonical_path ((*i));
3354 cerr << "\t => " << tmppath2 << endl;
3356 if (tmppath1 == tmppath2) {
3363 unused.push_back (spath);
3367 cerr << "Actually unused: " << unused.size() << endl;
3369 if (unused.empty()) {
3375 /* now try to move all unused files into the "dead" directory(ies) */
3377 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3382 /* don't move the file across filesystems, just
3383 * stick it in the `dead_dir_name' directory
3384 * on whichever filesystem it was already on.
3387 if ((*x).find ("/sounds/") != string::npos) {
3389 /* old school, go up 1 level */
3391 newpath = Glib::path_get_dirname (*x); // "sounds"
3392 newpath = Glib::path_get_dirname (newpath); // "session-name"
3396 /* new school, go up 4 levels */
3398 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3399 newpath = Glib::path_get_dirname (newpath); // "session-name"
3400 newpath = Glib::path_get_dirname (newpath); // "interchange"
3401 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3404 newpath = Glib::build_filename (newpath, dead_dir_name);
3406 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3407 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3411 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3413 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3415 /* the new path already exists, try versioning */
3417 char buf[PATH_MAX+1];
3421 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3424 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3425 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3429 if (version == 999) {
3430 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3434 newpath = newpath_v;
3439 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3440 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3441 newpath, g_strerror (errno)) << endmsg;
3445 /* see if there an easy to find peakfile for this file, and remove it. */
3447 string base = Glib::path_get_basename (*x);
3448 base += "%A"; /* this is what we add for the channel suffix of all native files,
3449 * or for the first channel of embedded files. it will miss
3450 * some peakfiles for other channels
3452 string peakpath = construct_peak_filepath (base);
3454 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3455 if (::g_unlink (peakpath.c_str ()) != 0) {
3456 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3457 g_strerror (errno)) << endmsg;
3458 /* try to back out */
3459 ::g_rename (newpath.c_str (), _path.c_str ());
3464 rep.paths.push_back (*x);
3465 rep.space += statbuf.st_size;
3468 /* dump the history list */
3472 /* save state so we don't end up a session file
3473 * referring to non-existent sources.
3480 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3486 Session::cleanup_trash_sources (CleanupReport& rep)
3488 // FIXME: needs adaptation for MIDI
3490 vector<space_and_path>::iterator i;
3496 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3498 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3500 clear_directory (dead_dir, &rep.space, &rep.paths);
3507 Session::set_dirty ()
3509 /* return early if there's nothing to do */
3514 /* never mark session dirty during loading */
3515 if (_state_of_the_state & Loading) {
3519 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3520 DirtyChanged(); /* EMIT SIGNAL */
3524 Session::set_clean ()
3526 bool was_dirty = dirty();
3528 _state_of_the_state = Clean;
3531 DirtyChanged(); /* EMIT SIGNAL */
3536 Session::set_deletion_in_progress ()
3538 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3542 Session::clear_deletion_in_progress ()
3544 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3548 Session::add_controllable (boost::shared_ptr<Controllable> c)
3550 /* this adds a controllable to the list managed by the Session.
3551 this is a subset of those managed by the Controllable class
3552 itself, and represents the only ones whose state will be saved
3553 as part of the session.
3556 Glib::Threads::Mutex::Lock lm (controllables_lock);
3557 controllables.insert (c);
3560 struct null_deleter { void operator()(void const *) const {} };
3563 Session::remove_controllable (Controllable* c)
3565 if (_state_of_the_state & Deletion) {
3569 Glib::Threads::Mutex::Lock lm (controllables_lock);
3571 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3573 if (x != controllables.end()) {
3574 controllables.erase (x);
3578 boost::shared_ptr<Controllable>
3579 Session::controllable_by_id (const PBD::ID& id)
3581 Glib::Threads::Mutex::Lock lm (controllables_lock);
3583 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3584 if ((*i)->id() == id) {
3589 return boost::shared_ptr<Controllable>();
3592 boost::shared_ptr<AutomationControl>
3593 Session::automation_control_by_id (const PBD::ID& id)
3595 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3598 boost::shared_ptr<Controllable>
3599 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3601 boost::shared_ptr<Controllable> c;
3602 boost::shared_ptr<Stripable> s;
3603 boost::shared_ptr<Route> r;
3605 switch (desc.top_level_type()) {
3606 case ControllableDescriptor::NamedRoute:
3608 std::string str = desc.top_level_name();
3610 if (str == "Master" || str == "master") {
3612 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3614 } else if (str == "auditioner") {
3617 s = route_by_name (desc.top_level_name());
3623 case ControllableDescriptor::PresentationOrderRoute:
3624 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3627 case ControllableDescriptor::PresentationOrderTrack:
3628 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3631 case ControllableDescriptor::PresentationOrderBus:
3632 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3635 case ControllableDescriptor::PresentationOrderVCA:
3636 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3639 case ControllableDescriptor::SelectionCount:
3640 s = route_by_selected_count (desc.selection_id());
3648 r = boost::dynamic_pointer_cast<Route> (s);
3650 switch (desc.subtype()) {
3651 case ControllableDescriptor::Gain:
3652 c = s->gain_control ();
3655 case ControllableDescriptor::Trim:
3656 c = s->trim_control ();
3659 case ControllableDescriptor::Solo:
3660 c = s->solo_control();
3663 case ControllableDescriptor::Mute:
3664 c = s->mute_control();
3667 case ControllableDescriptor::Recenable:
3668 c = s->rec_enable_control ();
3671 case ControllableDescriptor::PanDirection:
3672 c = s->pan_azimuth_control();
3675 case ControllableDescriptor::PanWidth:
3676 c = s->pan_width_control();
3679 case ControllableDescriptor::PanElevation:
3680 c = s->pan_elevation_control();
3683 case ControllableDescriptor::Balance:
3684 /* XXX simple pan control */
3687 case ControllableDescriptor::PluginParameter:
3689 uint32_t plugin = desc.target (0);
3690 uint32_t parameter_index = desc.target (1);
3692 /* revert to zero based counting */
3698 if (parameter_index > 0) {
3706 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3709 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3710 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3715 case ControllableDescriptor::SendGain: {
3716 uint32_t send = desc.target (0);
3723 c = r->send_level_controllable (send);
3728 /* relax and return a null pointer */
3736 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3739 Stateful::add_instant_xml (node, _path);
3742 if (write_to_config) {
3743 Config->add_instant_xml (node);
3748 Session::instant_xml (const string& node_name)
3750 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3751 if (get_disable_all_loaded_plugins ()) {
3755 return Stateful::instant_xml (node_name, _path);
3759 Session::save_history (string snapshot_name)
3767 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3768 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3772 if (snapshot_name.empty()) {
3773 snapshot_name = _current_snapshot_name;
3776 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3777 const string backup_filename = history_filename + backup_suffix;
3778 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3779 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3781 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3782 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3783 error << _("could not backup old history file, current history not saved") << endmsg;
3788 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3790 if (!tree.write (xml_path))
3792 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3794 if (g_remove (xml_path.c_str()) != 0) {
3795 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3796 xml_path, g_strerror (errno)) << endmsg;
3798 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3799 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3800 backup_path, g_strerror (errno)) << endmsg;
3810 Session::restore_history (string snapshot_name)
3814 if (snapshot_name.empty()) {
3815 snapshot_name = _current_snapshot_name;
3818 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3819 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3821 info << "Loading history from " << xml_path << endmsg;
3823 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3824 info << string_compose (_("%1: no history file \"%2\" for this session."),
3825 _name, xml_path) << endmsg;
3829 if (!tree.read (xml_path)) {
3830 error << string_compose (_("Could not understand session history file \"%1\""),
3831 xml_path) << endmsg;
3838 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3841 UndoTransaction* ut = new UndoTransaction ();
3847 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3848 !t->get_property ("tv-usec", tv_usec)) {
3852 ut->set_name (name);
3856 tv.tv_usec = tv_usec;
3857 ut->set_timestamp(tv);
3859 for (XMLNodeConstIterator child_it = t->children().begin();
3860 child_it != t->children().end(); child_it++)
3862 XMLNode *n = *child_it;
3865 if (n->name() == "MementoCommand" ||
3866 n->name() == "MementoUndoCommand" ||
3867 n->name() == "MementoRedoCommand") {
3869 if ((c = memento_command_factory(n))) {
3873 } else if (n->name() == "NoteDiffCommand") {
3874 PBD::ID id (n->property("midi-source")->value());
3875 boost::shared_ptr<MidiSource> midi_source =
3876 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3878 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3880 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3883 } else if (n->name() == "SysExDiffCommand") {
3885 PBD::ID id (n->property("midi-source")->value());
3886 boost::shared_ptr<MidiSource> midi_source =
3887 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3889 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3891 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3894 } else if (n->name() == "PatchChangeDiffCommand") {
3896 PBD::ID id (n->property("midi-source")->value());
3897 boost::shared_ptr<MidiSource> midi_source =
3898 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3900 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3902 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3905 } else if (n->name() == "StatefulDiffCommand") {
3906 if ((c = stateful_diff_command_factory (n))) {
3907 ut->add_command (c);
3910 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3921 Session::config_changed (std::string p, bool ours)
3927 if (p == "seamless-loop") {
3929 } else if (p == "rf-speed") {
3931 } else if (p == "auto-loop") {
3933 } else if (p == "session-monitoring") {
3935 } else if (p == "auto-input") {
3937 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3938 /* auto-input only makes a difference if we're rolling */
3939 set_track_monitor_input_status (!config.get_auto_input());
3942 } else if (p == "punch-in") {
3946 if ((location = _locations->auto_punch_location()) != 0) {
3948 if (config.get_punch_in ()) {
3949 replace_event (SessionEvent::PunchIn, location->start());
3951 remove_event (location->start(), SessionEvent::PunchIn);
3955 } else if (p == "punch-out") {
3959 if ((location = _locations->auto_punch_location()) != 0) {
3961 if (config.get_punch_out()) {
3962 replace_event (SessionEvent::PunchOut, location->end());
3964 clear_events (SessionEvent::PunchOut);
3968 } else if (p == "edit-mode") {
3970 Glib::Threads::Mutex::Lock lm (playlists->lock);
3972 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3973 (*i)->set_edit_mode (Config->get_edit_mode ());
3976 } else if (p == "use-video-sync") {
3978 waiting_for_sync_offset = config.get_use_video_sync();
3980 } else if (p == "mmc-control") {
3982 //poke_midi_thread ();
3984 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3986 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3988 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3990 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3992 } else if (p == "midi-control") {
3994 //poke_midi_thread ();
3996 } else if (p == "raid-path") {
3998 setup_raid_path (config.get_raid_path());
4000 } else if (p == "timecode-format") {
4004 } else if (p == "video-pullup") {
4008 } else if (p == "seamless-loop") {
4010 if (play_loop && transport_rolling()) {
4011 // to reset diskstreams etc
4012 request_play_loop (true);
4015 } else if (p == "rf-speed") {
4017 cumulative_rf_motion = 0;
4020 } else if (p == "click-sound") {
4022 setup_click_sounds (1);
4024 } else if (p == "click-emphasis-sound") {
4026 setup_click_sounds (-1);
4028 } else if (p == "clicking") {
4030 if (Config->get_clicking()) {
4031 if (_click_io && click_data) { // don't require emphasis data
4038 } else if (p == "click-record-only") {
4040 _click_rec_only = Config->get_click_record_only();
4042 } else if (p == "click-gain") {
4045 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4048 } else if (p == "send-mtc") {
4050 if (Config->get_send_mtc ()) {
4051 /* mark us ready to send */
4052 next_quarter_frame_to_send = 0;
4055 } else if (p == "send-mmc") {
4057 _mmc->enable_send (Config->get_send_mmc ());
4059 } else if (p == "jack-time-master") {
4061 engine().reset_timebase ();
4063 } else if (p == "native-file-header-format") {
4065 if (!first_file_header_format_reset) {
4066 reset_native_file_format ();
4069 first_file_header_format_reset = false;
4071 } else if (p == "native-file-data-format") {
4073 if (!first_file_data_format_reset) {
4074 reset_native_file_format ();
4077 first_file_data_format_reset = false;
4079 } else if (p == "external-sync") {
4080 if (!config.get_external_sync()) {
4081 drop_sync_source ();
4083 switch_to_sync_source (Config->get_sync_source());
4085 } else if (p == "denormal-model") {
4087 } else if (p == "history-depth") {
4088 set_history_depth (Config->get_history_depth());
4089 } else if (p == "remote-model") {
4090 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4093 } else if (p == "initial-program-change") {
4095 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4098 buf[0] = MIDI::program; // channel zero by default
4099 buf[1] = (Config->get_initial_program_change() & 0x7f);
4101 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4103 } else if (p == "solo-mute-override") {
4104 // catch_up_on_solo_mute_override ();
4105 } else if (p == "listen-position" || p == "pfl-position") {
4106 listen_position_changed ();
4107 } else if (p == "solo-control-is-listen-control") {
4108 solo_control_mode_changed ();
4109 } else if (p == "solo-mute-gain") {
4110 _solo_cut_control->Changed (true, Controllable::NoGroup);
4111 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4112 last_timecode_valid = false;
4113 } else if (p == "playback-buffer-seconds") {
4114 AudioSource::allocate_working_buffers (frame_rate());
4115 } else if (p == "ltc-source-port") {
4116 reconnect_ltc_input ();
4117 } else if (p == "ltc-sink-port") {
4118 reconnect_ltc_output ();
4119 } else if (p == "timecode-generator-offset") {
4120 ltc_tx_parse_offset();
4121 } else if (p == "auto-return-target-list") {
4122 follow_playhead_priority ();
4129 Session::set_history_depth (uint32_t d)
4131 _history.set_depth (d);
4135 Session::load_diskstreams_2X (XMLNode const & node, int)
4138 XMLNodeConstIterator citer;
4140 clist = node.children();
4142 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4145 /* diskstreams added automatically by DiskstreamCreated handler */
4146 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4147 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4148 _diskstreams_2X.push_back (dsp);
4150 error << _("Session: unknown diskstream type in XML") << endmsg;
4154 catch (failed_constructor& err) {
4155 error << _("Session: could not load diskstream via XML state") << endmsg;
4163 /** Connect things to the MMC object */
4165 Session::setup_midi_machine_control ()
4167 _mmc = new MIDI::MachineControl;
4169 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4170 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4172 if (!async_out || !async_out) {
4176 /* XXXX argh, passing raw pointers back into libmidi++ */
4178 MIDI::Port* mmc_in = async_in.get();
4179 MIDI::Port* mmc_out = async_out.get();
4181 _mmc->set_ports (mmc_in, mmc_out);
4183 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4184 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4185 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4186 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4187 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4188 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4189 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4190 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4191 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4192 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4193 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4194 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4195 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4197 /* also handle MIDI SPP because its so common */
4199 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4200 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4201 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4204 boost::shared_ptr<Controllable>
4205 Session::solo_cut_control() const
4207 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4208 * controls in Ardour that currently get presented to the user in the GUI that require
4209 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4211 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4212 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4215 return _solo_cut_control;
4219 Session::save_snapshot_name (const std::string & n)
4221 /* assure Stateful::_instant_xml is loaded
4222 * add_instant_xml() only adds to existing data and defaults
4223 * to use an empty Tree otherwise
4225 instant_xml ("LastUsedSnapshot");
4227 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4228 last_used_snapshot->set_property ("name", n);
4229 add_instant_xml (*last_used_snapshot, false);
4233 Session::set_snapshot_name (const std::string & n)
4235 _current_snapshot_name = n;
4236 save_snapshot_name (n);
4240 Session::rename (const std::string& new_name)
4242 string legal_name = legalize_for_path (new_name);
4248 string const old_sources_root = _session_dir->sources_root();
4250 if (!_writable || (_state_of_the_state & CannotSave)) {
4251 error << _("Cannot rename read-only session.") << endmsg;
4252 return 0; // don't show "messed up" warning
4254 if (record_status() == Recording) {
4255 error << _("Cannot rename session while recording") << endmsg;
4256 return 0; // don't show "messed up" warning
4259 StateProtector stp (this);
4264 * interchange subdirectory
4268 * Backup files are left unchanged and not renamed.
4271 /* Windows requires that we close all files before attempting the
4272 * rename. This works on other platforms, but isn't necessary there.
4273 * Leave it in place for all platforms though, since it may help
4274 * catch issues that could arise if the way Source files work ever
4275 * change (since most developers are not using Windows).
4278 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4279 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4285 /* pass one: not 100% safe check that the new directory names don't
4289 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4293 /* this is a stupid hack because Glib::path_get_dirname() is
4294 * lexical-only, and so passing it /a/b/c/ gives a different
4295 * result than passing it /a/b/c ...
4298 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4299 oldstr = oldstr.substr (0, oldstr.length() - 1);
4302 string base = Glib::path_get_dirname (oldstr);
4304 newstr = Glib::build_filename (base, legal_name);
4306 cerr << "Looking for " << newstr << endl;
4308 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4309 cerr << " exists\n";
4318 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4324 /* this is a stupid hack because Glib::path_get_dirname() is
4325 * lexical-only, and so passing it /a/b/c/ gives a different
4326 * result than passing it /a/b/c ...
4329 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4330 oldstr = oldstr.substr (0, oldstr.length() - 1);
4333 string base = Glib::path_get_dirname (oldstr);
4334 newstr = Glib::build_filename (base, legal_name);
4336 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4338 cerr << "Rename " << oldstr << " => " << newstr << endl;
4339 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4340 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4341 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4345 /* Reset path in "session dirs" */
4350 /* reset primary SessionDirectory object */
4353 (*_session_dir) = newstr;
4358 /* now rename directory below session_dir/interchange */
4360 string old_interchange_dir;
4361 string new_interchange_dir;
4363 /* use newstr here because we renamed the path
4364 * (folder/directory) that used to be oldstr to newstr above
4367 v.push_back (newstr);
4368 v.push_back (interchange_dir_name);
4369 v.push_back (Glib::path_get_basename (oldstr));
4371 old_interchange_dir = Glib::build_filename (v);
4374 v.push_back (newstr);
4375 v.push_back (interchange_dir_name);
4376 v.push_back (legal_name);
4378 new_interchange_dir = Glib::build_filename (v);
4380 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4382 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4383 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4384 old_interchange_dir, new_interchange_dir,
4387 error << string_compose (_("renaming %s as %2 failed (%3)"),
4388 old_interchange_dir, new_interchange_dir,
4397 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4398 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4400 cerr << "Rename " << oldstr << " => " << newstr << endl;
4402 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4403 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4404 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4410 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4412 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4413 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4415 cerr << "Rename " << oldstr << " => " << newstr << endl;
4417 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4418 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4419 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4424 /* remove old name from recent sessions */
4425 remove_recent_sessions (_path);
4428 /* update file source paths */
4430 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4431 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4433 string p = fs->path ();
4434 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4436 SourceFactory::setup_peakfile(i->second, true);
4440 set_snapshot_name (new_name);
4445 /* save state again to get everything just right */
4447 save_state (_current_snapshot_name);
4449 /* add to recent sessions */
4451 store_recent_sessions (new_name, _path);
4457 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4459 bool found_sr = false;
4460 bool found_data_format = false;
4461 program_version = "";
4463 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4467 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4471 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4474 xmlFreeParserCtxt(ctxt);
4478 xmlNodePtr node = xmlDocGetRootElement(doc);
4481 xmlFreeParserCtxt(ctxt);
4489 for (attr = node->properties; attr; attr = attr->next) {
4490 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4491 sample_rate = atoi ((char*)attr->children->content);
4496 node = node->children;
4497 while (node != NULL) {
4498 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4499 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4501 program_version = string ((const char*)val);
4502 size_t sep = program_version.find_first_of("-");
4503 if (sep != string::npos) {
4504 program_version = program_version.substr (0, sep);
4509 if (strcmp((const char*) node->name, "Config")) {
4513 for (node = node->children; node; node = node->next) {
4514 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4515 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4517 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4519 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4521 found_data_format = true;
4531 xmlFreeParserCtxt(ctxt);
4534 return !(found_sr && found_data_format); // zero if they are both found
4538 Session::get_snapshot_from_instant (const std::string& session_dir)
4540 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4542 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4547 if (!tree.read (instant_xml_path)) {
4551 XMLProperty const * prop;
4552 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4553 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4554 return prop->value();
4560 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4561 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4564 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4568 SourcePathMap source_path_map;
4570 boost::shared_ptr<AudioFileSource> afs;
4575 Glib::Threads::Mutex::Lock lm (source_lock);
4577 cerr << " total sources = " << sources.size();
4579 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4580 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4586 if (fs->within_session()) {
4590 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4591 source_path_map[fs->path()].push_back (fs);
4593 SeveralFileSources v;
4595 source_path_map.insert (make_pair (fs->path(), v));
4601 cerr << " fsources = " << total << endl;
4603 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4605 /* tell caller where we are */
4607 string old_path = i->first;
4609 callback (n, total, old_path);
4611 cerr << old_path << endl;
4615 switch (i->second.front()->type()) {
4616 case DataType::AUDIO:
4617 new_path = new_audio_source_path_for_embedded (old_path);
4620 case DataType::MIDI:
4621 /* XXX not implemented yet */
4625 if (new_path.empty()) {
4629 cerr << "Move " << old_path << " => " << new_path << endl;
4631 if (!copy_file (old_path, new_path)) {
4632 cerr << "failed !\n";
4636 /* make sure we stop looking in the external
4637 dir/folder. Remember, this is an all-or-nothing
4638 operations, it doesn't merge just some files.
4640 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4642 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4643 (*f)->set_path (new_path);
4648 save_state ("", false, false);
4654 bool accept_all_files (string const &, void *)
4660 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4662 /* 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.
4667 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4669 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4671 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4673 v.push_back (new_session_folder); /* full path */
4674 v.push_back (interchange_dir_name);
4675 v.push_back (new_session_path); /* just one directory/folder */
4676 v.push_back (typedir);
4677 v.push_back (Glib::path_get_basename (old_path));
4679 return Glib::build_filename (v);
4683 Session::save_as (SaveAs& saveas)
4685 vector<string> files;
4686 string current_folder = Glib::path_get_dirname (_path);
4687 string new_folder = legalize_for_path (saveas.new_name);
4688 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4689 int64_t total_bytes = 0;
4693 int32_t internal_file_cnt = 0;
4695 vector<string> do_not_copy_extensions;
4696 do_not_copy_extensions.push_back (statefile_suffix);
4697 do_not_copy_extensions.push_back (pending_suffix);
4698 do_not_copy_extensions.push_back (backup_suffix);
4699 do_not_copy_extensions.push_back (temp_suffix);
4700 do_not_copy_extensions.push_back (history_suffix);
4702 /* get total size */
4704 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4706 /* need to clear this because
4707 * find_files_matching_filter() is cumulative
4712 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4714 all += files.size();
4716 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4718 g_stat ((*i).c_str(), &gsb);
4719 total_bytes += gsb.st_size;
4723 /* save old values so we can switch back if we are not switching to the new session */
4725 string old_path = _path;
4726 string old_name = _name;
4727 string old_snapshot = _current_snapshot_name;
4728 string old_sd = _session_dir->root_path();
4729 vector<string> old_search_path[DataType::num_types];
4730 string old_config_search_path[DataType::num_types];
4732 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4733 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4734 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4735 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4737 /* switch session directory */
4739 (*_session_dir) = to_dir;
4741 /* create new tree */
4743 if (!_session_dir->create()) {
4744 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4749 /* copy all relevant files. Find each location in session_dirs,
4750 * and copy files from there to target.
4753 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4755 /* need to clear this because
4756 * find_files_matching_filter() is cumulative
4761 const size_t prefix_len = (*sd).path.size();
4763 /* Work just on the files within this session dir */
4765 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4767 /* add dir separator to protect against collisions with
4768 * track names (e.g. track named "audiofiles" or
4772 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4773 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4774 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4776 /* copy all the files. Handling is different for media files
4777 than others because of the *silly* subtree we have below the interchange
4778 folder. That really was a bad idea, but I'm not fixing it as part of
4779 implementing ::save_as().
4782 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4784 std::string from = *i;
4787 string filename = Glib::path_get_basename (from);
4788 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4789 if (filename == ".DS_STORE") {
4794 if (from.find (audiofile_dir_string) != string::npos) {
4796 /* audio file: only copy if asked */
4798 if (saveas.include_media && saveas.copy_media) {
4800 string to = make_new_media_path (*i, to_dir, new_folder);
4802 info << "media file copying from " << from << " to " << to << endmsg;
4804 if (!copy_file (from, to)) {
4805 throw Glib::FileError (Glib::FileError::IO_ERROR,
4806 string_compose(_("\ncopying \"%1\" failed !"), from));
4810 /* we found media files inside the session folder */
4812 internal_file_cnt++;
4814 } else if (from.find (midifile_dir_string) != string::npos) {
4816 /* midi file: always copy unless
4817 * creating an empty new session
4820 if (saveas.include_media) {
4822 string to = make_new_media_path (*i, to_dir, new_folder);
4824 info << "media file copying from " << from << " to " << to << endmsg;
4826 if (!copy_file (from, to)) {
4827 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4831 /* we found media files inside the session folder */
4833 internal_file_cnt++;
4835 } else if (from.find (analysis_dir_string) != string::npos) {
4837 /* make sure analysis dir exists in
4838 * new session folder, but we're not
4839 * copying analysis files here, see
4843 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4848 /* normal non-media file. Don't copy state, history, etc.
4851 bool do_copy = true;
4853 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4854 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4855 /* end of filename matches extension, do not copy file */
4861 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4862 /* don't copy peakfiles if
4863 * we're not copying media
4869 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4871 info << "attempting to make directory/folder " << to << endmsg;
4873 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4874 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4877 info << "attempting to copy " << from << " to " << to << endmsg;
4879 if (!copy_file (from, to)) {
4880 throw Glib::FileError (Glib::FileError::IO_ERROR,
4881 string_compose(_("\ncopying \"%1\" failed !"), from));
4886 /* measure file size even if we're not going to copy so that our Progress
4887 signals are correct, since we included these do-not-copy files
4888 in the computation of the total size and file count.
4892 g_stat (from.c_str(), &gsb);
4893 copied += gsb.st_size;
4896 double fraction = (double) copied / total_bytes;
4898 bool keep_going = true;
4900 if (saveas.copy_media) {
4902 /* no need or expectation of this if
4903 * media is not being copied, because
4904 * it will be fast(ish).
4907 /* tell someone "X percent, file M of N"; M is one-based */
4909 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4917 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4923 /* copy optional folders, if any */
4925 string old = plugins_dir ();
4926 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4927 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4928 copy_files (old, newdir);
4931 old = externals_dir ();
4932 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4933 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4934 copy_files (old, newdir);
4937 old = automation_dir ();
4938 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4939 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4940 copy_files (old, newdir);
4943 if (saveas.include_media) {
4945 if (saveas.copy_media) {
4946 #ifndef PLATFORM_WINDOWS
4947 /* There are problems with analysis files on
4948 * Windows, because they used a colon in their
4949 * names as late as 4.0. Colons are not legal
4950 * under Windows even if NTFS allows them.
4952 * This is a tricky problem to solve so for
4953 * just don't copy these files. They will be
4954 * regenerated as-needed anyway, subject to the
4955 * existing issue that the filenames will be
4956 * rejected by Windows, which is a separate
4957 * problem (though related).
4960 /* only needed if we are copying media, since the
4961 * analysis data refers to media data
4964 old = analysis_dir ();
4965 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4966 string newdir = Glib::build_filename (to_dir, "analysis");
4967 copy_files (old, newdir);
4969 #endif /* PLATFORM_WINDOWS */
4974 set_snapshot_name (saveas.new_name);
4975 _name = saveas.new_name;
4977 if (saveas.include_media && !saveas.copy_media) {
4979 /* reset search paths of the new session (which we're pretending to be right now) to
4980 include the original session search path, so we can still find all audio.
4983 if (internal_file_cnt) {
4984 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4985 ensure_search_path_includes (*s, DataType::AUDIO);
4986 cerr << "be sure to include " << *s << " for audio" << endl;
4989 /* we do not do this for MIDI because we copy
4990 all MIDI files if saveas.include_media is
4996 bool was_dirty = dirty ();
4998 save_default_options ();
5000 if (saveas.copy_media && saveas.copy_external) {
5001 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5002 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5006 saveas.final_session_folder_name = _path;
5008 store_recent_sessions (_name, _path);
5010 if (!saveas.switch_to) {
5012 /* save the new state */
5014 save_state ("", false, false, !saveas.include_media);
5016 /* switch back to the way things were */
5020 set_snapshot_name (old_snapshot);
5022 (*_session_dir) = old_sd;
5028 if (internal_file_cnt) {
5029 /* reset these to their original values */
5030 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5031 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5036 /* prune session dirs, and update disk space statistics
5041 session_dirs.clear ();
5042 session_dirs.push_back (sp);
5043 refresh_disk_space ();
5045 _writable = exists_and_writable (_path);
5047 /* ensure that all existing tracks reset their current capture source paths
5049 reset_write_sources (true, true);
5051 /* creating new write sources marks the session as
5052 dirty. If the new session is empty, then
5053 save_state() thinks we're saving a template and will
5054 not mark the session as clean. So do that here,
5055 before we save state.
5058 if (!saveas.include_media) {
5059 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5062 save_state ("", false, false, !saveas.include_media);
5064 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5065 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5068 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5069 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5075 if (fs->within_session()) {
5076 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5077 fs->set_path (newpath);
5082 } catch (Glib::FileError& e) {
5084 saveas.failure_message = e.what();
5086 /* recursively remove all the directories */
5088 remove_directory (to_dir);
5096 saveas.failure_message = _("unknown reason");
5098 /* recursively remove all the directories */
5100 remove_directory (to_dir);
5110 static void set_progress (Progress* p, size_t n, size_t t)
5112 p->set_progress (float (n) / float(t));
5116 Session::archive_session (const std::string& dest,
5117 const std::string& name,
5118 ArchiveEncode compress_audio,
5119 bool only_used_sources,
5122 if (dest.empty () || name.empty ()) {
5126 /* save current values */
5127 bool was_dirty = dirty ();
5128 string old_path = _path;
5129 string old_name = _name;
5130 string old_snapshot = _current_snapshot_name;
5131 string old_sd = _session_dir->root_path();
5132 string old_config_search_path[DataType::num_types];
5133 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5134 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5136 /* ensure that session-path is included in search-path */
5138 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5139 if ((*sd).path == old_path) {
5147 /* create temporary dir to save session to */
5148 #ifdef PLATFORM_WINDOWS
5149 char tmp[256] = "C:\\TEMP\\";
5150 GetTempPath (sizeof (tmp), tmp);
5152 char const* tmp = getenv("TMPDIR");
5157 if ((strlen (tmp) + 21) > 1024) {
5162 strcpy (tmptpl, tmp);
5163 strcat (tmptpl, "ardourarchive-XXXXXX");
5164 char* tmpdir = g_mkdtemp (tmptpl);
5170 std::string to_dir = std::string (tmpdir);
5172 /* switch session directory temporarily */
5173 (*_session_dir) = to_dir;
5175 if (!_session_dir->create()) {
5176 (*_session_dir) = old_sd;
5177 remove_directory (to_dir);
5181 /* prepare archive */
5182 string archive = Glib::build_filename (dest, name + ".tar.xz");
5184 PBD::ScopedConnectionList progress_connection;
5185 PBD::FileArchive ar (archive);
5187 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5190 /* collect files to archive */
5191 std::map<string,string> filemap;
5193 vector<string> do_not_copy_extensions;
5194 do_not_copy_extensions.push_back (statefile_suffix);
5195 do_not_copy_extensions.push_back (pending_suffix);
5196 do_not_copy_extensions.push_back (backup_suffix);
5197 do_not_copy_extensions.push_back (temp_suffix);
5198 do_not_copy_extensions.push_back (history_suffix);
5200 vector<string> blacklist_dirs;
5201 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5202 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5203 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5204 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5205 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5206 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5208 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5209 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5211 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5212 if (only_used_sources) {
5213 playlists->sync_all_regions_with_regions ();
5214 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5217 // collect audio sources for this session, calc total size for encoding
5218 // add option to only include *used* sources (see Session::cleanup_sources)
5219 size_t total_size = 0;
5221 Glib::Threads::Mutex::Lock lm (source_lock);
5222 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5223 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5224 if (!afs || afs->readable_length () == 0) {
5228 if (only_used_sources) {
5232 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5237 std::string from = afs->path();
5239 if (compress_audio != NO_ENCODE) {
5240 total_size += afs->readable_length ();
5242 if (afs->within_session()) {
5243 filemap[from] = make_new_media_path (from, name, name);
5245 filemap[from] = make_new_media_path (from, name, name);
5246 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5253 if (compress_audio != NO_ENCODE) {
5255 progress->set_progress (2); // set to "encoding"
5256 progress->set_progress (0);
5259 Glib::Threads::Mutex::Lock lm (source_lock);
5260 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5261 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5262 if (!afs || afs->readable_length () == 0) {
5266 if (only_used_sources) {
5270 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5275 orig_sources[afs] = afs->path();
5276 orig_gain[afs] = afs->gain();
5278 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5279 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5280 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5283 progress->descend ((float)afs->readable_length () / total_size);
5287 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5288 afs->replace_file (new_path);
5289 afs->set_gain (ns->gain(), true);
5292 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5296 progress->ascend ();
5302 progress->set_progress (-1); // set to "archiving"
5303 progress->set_progress (0);
5306 /* index files relevant for this session */
5307 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5308 vector<string> files;
5310 size_t prefix_len = (*sd).path.size();
5311 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5315 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5317 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5318 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5319 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5321 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5322 std::string from = *i;
5325 string filename = Glib::path_get_basename (from);
5326 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5327 if (filename == ".DS_STORE") {
5332 if (from.find (audiofile_dir_string) != string::npos) {
5334 } else if (from.find (midifile_dir_string) != string::npos) {
5335 filemap[from] = make_new_media_path (from, name, name);
5336 } else if (from.find (videofile_dir_string) != string::npos) {
5337 filemap[from] = make_new_media_path (from, name, name);
5339 bool do_copy = true;
5340 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5341 if (from.find (*v) != string::npos) {
5346 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5347 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5354 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5360 /* write session file */
5362 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5364 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5367 save_default_options ();
5369 size_t prefix_len = _path.size();
5370 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5374 /* collect session-state files */
5375 vector<string> files;
5376 do_not_copy_extensions.clear ();
5377 do_not_copy_extensions.push_back (history_suffix);
5379 blacklist_dirs.clear ();
5380 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5382 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5383 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5384 std::string from = *i;
5385 bool do_copy = true;
5386 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5387 if (from.find (*v) != string::npos) {
5392 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5393 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5399 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5403 /* restore original values */
5406 set_snapshot_name (old_snapshot);
5407 (*_session_dir) = old_sd;
5411 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5412 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5414 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5415 i->first->replace_file (i->second);
5417 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5418 i->first->set_gain (i->second, true);
5421 int rv = ar.create (filemap);
5422 remove_directory (to_dir);
5428 Session::undo (uint32_t n)
5430 if (actively_recording()) {
5438 Session::redo (uint32_t n)
5440 if (actively_recording()) {