2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
53 #include "pbd/locale_guard.h"
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/basename.h"
67 #include "pbd/debug.h"
68 #include "pbd/enumwriter.h"
69 #include "pbd/error.h"
70 #include "pbd/file_archive.h"
71 #include "pbd/file_utils.h"
72 #include "pbd/pathexpand.h"
73 #include "pbd/pthread_utils.h"
74 #include "pbd/stacktrace.h"
75 #include "pbd/types_convert.h"
76 #include "pbd/localtime_r.h"
77 #include "pbd/unwind.h"
79 #include "ardour/amp.h"
80 #include "ardour/async_midi_port.h"
81 #include "ardour/audio_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/disk_reader.h"
93 #include "ardour/filename_extensions.h"
94 #include "ardour/graph.h"
95 #include "ardour/location.h"
97 #include "ardour/lv2_plugin.h"
99 #include "ardour/midi_model.h"
100 #include "ardour/midi_patch_manager.h"
101 #include "ardour/midi_region.h"
102 #include "ardour/midi_scene_changer.h"
103 #include "ardour/midi_source.h"
104 #include "ardour/midi_track.h"
105 #include "ardour/pannable.h"
106 #include "ardour/playlist_factory.h"
107 #include "ardour/playlist_source.h"
108 #include "ardour/port.h"
109 #include "ardour/processor.h"
110 #include "ardour/progress.h"
111 #include "ardour/profile.h"
112 #include "ardour/proxy_controllable.h"
113 #include "ardour/recent_sessions.h"
114 #include "ardour/region_factory.h"
115 #include "ardour/revision.h"
116 #include "ardour/route_group.h"
117 #include "ardour/send.h"
118 #include "ardour/selection.h"
119 #include "ardour/session.h"
120 #include "ardour/session_directory.h"
121 #include "ardour/session_metadata.h"
122 #include "ardour/session_playlists.h"
123 #include "ardour/session_state_utils.h"
124 #include "ardour/silentfilesource.h"
125 #include "ardour/smf_source.h"
126 #include "ardour/sndfilesource.h"
127 #include "ardour/source_factory.h"
128 #include "ardour/speakers.h"
129 #include "ardour/template_utils.h"
130 #include "ardour/tempo.h"
131 #include "ardour/ticker.h"
132 #include "ardour/types_convert.h"
133 #include "ardour/user_bundle.h"
134 #include "ardour/vca.h"
135 #include "ardour/vca_manager.h"
137 #include "control_protocol/control_protocol.h"
139 #include "LuaBridge/LuaBridge.h"
141 #include "pbd/i18n.h"
145 using namespace ARDOUR;
148 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
151 Session::pre_engine_init (string fullpath)
153 if (fullpath.empty()) {
155 throw failed_constructor();
158 /* discover canonical fullpath */
160 _path = canonical_path(fullpath);
163 if (Profile->get_trx() ) {
164 // Waves TracksLive has a usecase of session replacement with a new one.
165 // We should check session state file (<session_name>.ardour) existance
166 // to determine if the session is new or not
168 string full_session_name = Glib::build_filename( fullpath, _name );
169 full_session_name += statefile_suffix;
171 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
173 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
176 /* finish initialization that can't be done in a normal C++ constructor
180 timerclear (&last_mmc_step);
181 g_atomic_int_set (&processing_prohibited, 0);
182 g_atomic_int_set (&_record_status, Disabled);
183 g_atomic_int_set (&_playback_load, 100);
184 g_atomic_int_set (&_capture_load, 100);
186 _all_route_group->set_active (true, this);
187 interpolation.add_channel_to (0, 0);
189 if (config.get_use_video_sync()) {
190 waiting_for_sync_offset = true;
192 waiting_for_sync_offset = false;
195 last_rr_session_dir = session_dirs.begin();
197 set_history_depth (Config->get_history_depth());
199 /* default: assume simple stereo speaker configuration */
201 _speakers->setup_default_speakers (2);
203 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
204 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
205 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
206 add_controllable (_solo_cut_control);
208 /* These are all static "per-class" signals */
210 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
211 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
212 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
213 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
214 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
216 /* stop IO objects from doing stuff until we're ready for them */
218 Delivery::disable_panners ();
219 IO::disable_connecting ();
223 Session::post_engine_init ()
225 BootMessage (_("Set block size and sample rate"));
227 set_block_size (_engine.samples_per_cycle());
228 set_frame_rate (_engine.sample_rate());
230 BootMessage (_("Using configuration"));
232 _midi_ports = new MidiPortManager;
234 MIDISceneChanger* msc;
236 _scene_changer = msc = new MIDISceneChanger (*this);
237 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
238 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
240 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
241 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
243 setup_midi_machine_control ();
245 if (_butler->start_thread()) {
246 error << _("Butler did not start") << endmsg;
250 if (start_midi_thread ()) {
251 error << _("MIDI I/O thread did not start") << endmsg;
255 setup_click_sounds (0);
256 setup_midi_control ();
258 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
259 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
262 /* tempo map requires sample rate knowledge */
265 _tempo_map = new TempoMap (_current_frame_rate);
266 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
267 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
268 } catch (std::exception const & e) {
269 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
272 error << _("Unknown exception during session setup") << endmsg;
277 /* MidiClock requires a tempo map */
280 midi_clock = new MidiClockTicker ();
281 midi_clock->set_session (this);
283 /* crossfades require sample rate knowledge */
285 SndFileSource::setup_standard_crossfades (*this, frame_rate());
286 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
287 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
289 DiskReader::allocate_working_buffers();
290 refresh_disk_space ();
292 /* we're finally ready to call set_state() ... all objects have
293 * been created, the engine is running.
298 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
299 error << _("Could not set session state from XML") << endmsg;
302 } catch (PBD::unknown_enumeration& e) {
303 error << _("Session state: ") << e.what() << endmsg;
307 // set_state() will call setup_raid_path(), but if it's a new session we need
308 // to call setup_raid_path() here.
309 setup_raid_path (_path);
314 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
315 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
317 Config->map_parameters (ff);
318 config.map_parameters (ft);
319 _butler->map_parameters ();
321 /* Reset all panners */
323 Delivery::reset_panners ();
325 /* this will cause the CPM to instantiate any protocols that are in use
326 * (or mandatory), which will pass it this Session, and then call
327 * set_state() on each instantiated protocol to match stored state.
330 ControlProtocolManager::instance().set_session (this);
332 /* This must be done after the ControlProtocolManager set_session above,
333 as it will set states for ports which the ControlProtocolManager creates.
336 // XXX set state of MIDI::Port's
337 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
339 /* And this must be done after the MIDI::Manager::set_port_states as
340 * it will try to make connections whose details are loaded by set_port_states.
345 /* Let control protocols know that we are now all connected, so they
346 * could start talking to surfaces if they want to.
349 ControlProtocolManager::instance().midi_connectivity_established ();
351 if (_is_new && !no_auto_connect()) {
352 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
353 auto_connect_master_bus ();
356 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
358 /* update latencies */
360 initialize_latencies ();
362 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
363 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
364 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
366 } catch (AudioEngine::PortRegistrationFailure& err) {
367 error << err.what() << endmsg;
369 } catch (std::exception const & e) {
370 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
373 error << _("Unknown exception during session setup") << endmsg;
377 BootMessage (_("Reset Remote Controls"));
379 // send_full_time_code (0);
380 _engine.transport_locate (0);
382 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
383 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
385 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
388 /* initial program change will be delivered later; see ::config_changed() */
390 _state_of_the_state = Clean;
392 Port::set_connecting_blocked (false);
394 DirtyChanged (); /* EMIT SIGNAL */
398 } else if (state_was_pending) {
400 remove_pending_capture_state ();
401 state_was_pending = false;
404 /* Now, finally, we can fill the playback buffers */
406 BootMessage (_("Filling playback buffers"));
408 boost::shared_ptr<RouteList> rl = routes.reader();
409 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
410 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
411 if (trk && !trk->hidden()) {
412 trk->seek (_transport_frame, true);
420 Session::session_loaded ()
424 _state_of_the_state = Clean;
426 DirtyChanged (); /* EMIT SIGNAL */
430 } else if (state_was_pending) {
432 remove_pending_capture_state ();
433 state_was_pending = false;
436 /* Now, finally, we can fill the playback buffers */
438 BootMessage (_("Filling playback buffers"));
439 force_locate (_transport_frame, false);
443 Session::raid_path () const
445 Searchpath raid_search_path;
447 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
448 raid_search_path += (*i).path;
451 return raid_search_path.to_string ();
455 Session::setup_raid_path (string path)
464 session_dirs.clear ();
466 Searchpath search_path(path);
467 Searchpath sound_search_path;
468 Searchpath midi_search_path;
470 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
472 sp.blocks = 0; // not needed
473 session_dirs.push_back (sp);
475 SessionDirectory sdir(sp.path);
477 sound_search_path += sdir.sound_path ();
478 midi_search_path += sdir.midi_path ();
481 // reset the round-robin soundfile path thingie
482 last_rr_session_dir = session_dirs.begin();
486 Session::path_is_within_session (const std::string& path)
488 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
489 if (PBD::path_is_within (i->path, path)) {
497 Session::ensure_subdirs ()
501 dir = session_directory().peak_path();
503 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
504 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
508 dir = session_directory().sound_path();
510 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
511 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
515 dir = session_directory().midi_path();
517 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
518 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
522 dir = session_directory().dead_path();
524 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
525 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
529 dir = session_directory().export_path();
531 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
532 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
536 dir = analysis_dir ();
538 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
539 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
543 dir = plugins_dir ();
545 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
546 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
550 dir = externals_dir ();
552 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
553 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
560 /** @param session_template directory containing session template, or empty.
561 * Caller must not hold process lock.
564 Session::create (const string& session_template, BusProfile* bus_profile)
566 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
567 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
571 if (ensure_subdirs ()) {
575 _writable = exists_and_writable (_path);
577 if (!session_template.empty()) {
578 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
580 FILE* in = g_fopen (in_path.c_str(), "rb");
583 /* no need to call legalize_for_path() since the string
584 * in session_template is already a legal path name
586 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
588 FILE* out = g_fopen (out_path.c_str(), "wb");
592 stringstream new_session;
595 size_t charsRead = fread (buf, sizeof(char), 1024, in);
598 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
603 if (charsRead == 0) {
606 new_session.write (buf, charsRead);
610 string file_contents = new_session.str();
611 size_t writeSize = file_contents.length();
612 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
613 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
621 if (!ARDOUR::Profile->get_trx()) {
622 /* Copy plugin state files from template to new session */
623 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
624 copy_recurse (template_plugins, plugins_dir ());
630 error << string_compose (_("Could not open %1 for writing session template"), out_path)
637 error << string_compose (_("Could not open session template %1 for reading"), in_path)
644 if (Profile->get_trx()) {
646 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
647 * Remember that this is a brand new session. Sessions
648 * loaded from saved state will get this range from the saved state.
651 set_session_range_location (0, 0);
653 /* Initial loop location, from absolute zero, length 10 seconds */
655 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
656 _locations->add (loc, true);
657 set_auto_loop_location (loc);
660 _state_of_the_state = Clean;
662 /* set up Master Out and Monitor Out if necessary */
666 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
667 if (bus_profile->master_out_channels) {
668 int rv = add_master_bus (count);
674 if (Config->get_use_monitor_bus())
675 add_monitor_section ();
683 Session::maybe_write_autosave()
685 if (dirty() && record_status() != Recording) {
686 save_state("", true);
691 Session::remove_pending_capture_state ()
693 std::string pending_state_file_path(_session_dir->root_path());
695 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
697 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
699 if (g_remove (pending_state_file_path.c_str()) != 0) {
700 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
701 pending_state_file_path, g_strerror (errno)) << endmsg;
705 /** Rename a state file.
706 * @param old_name Old snapshot name.
707 * @param new_name New snapshot name.
710 Session::rename_state (string old_name, string new_name)
712 if (old_name == _current_snapshot_name || old_name == _name) {
713 /* refuse to rename the current snapshot or the "main" one */
717 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
718 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
720 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
721 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
723 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
724 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
725 old_name, new_name, g_strerror(errno)) << endmsg;
729 /** Remove a state file.
730 * @param snapshot_name Snapshot name.
733 Session::remove_state (string snapshot_name)
735 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
736 // refuse to remove the current snapshot or the "main" one
740 std::string xml_path(_session_dir->root_path());
742 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
744 if (!create_backup_file (xml_path)) {
745 // don't remove it if a backup can't be made
746 // create_backup_file will log the error.
751 if (g_remove (xml_path.c_str()) != 0) {
752 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
753 xml_path, g_strerror (errno)) << endmsg;
757 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
759 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
761 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
764 std::string xml_path(_session_dir->root_path());
766 /* prevent concurrent saves from different threads */
768 Glib::Threads::Mutex::Lock lm (save_state_lock);
770 if (!_writable || (_state_of_the_state & CannotSave)) {
774 if (g_atomic_int_get(&_suspend_save)) {
778 _save_queued = false;
780 snapshot_t fork_state = NormalSave;
781 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) {
782 /* snapshot, close midi */
783 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
787 const int64_t save_start_time = g_get_monotonic_time();
790 /* tell sources we're saving first, in case they write out to a new file
791 * which should be saved with the state rather than the old one */
792 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
794 i->second->session_saved();
795 } catch (Evoral::SMF::FileError& e) {
796 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
800 SessionSaveUnderway (); /* EMIT SIGNAL */
802 bool mark_as_clean = true;
804 if (!snapshot_name.empty() && !switch_to_snapshot) {
805 mark_as_clean = false;
809 mark_as_clean = false;
810 tree.set_root (&get_template());
812 tree.set_root (&state (true, fork_state));
815 if (snapshot_name.empty()) {
816 snapshot_name = _current_snapshot_name;
817 } else if (switch_to_snapshot) {
818 set_snapshot_name (snapshot_name);
821 assert (!snapshot_name.empty());
825 /* proper save: use statefile_suffix (.ardour in English) */
827 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
829 /* make a backup copy of the old file */
831 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
832 // create_backup_file will log the error
838 /* pending save: use pending_suffix (.pending in English) */
839 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
842 std::string tmp_path(_session_dir->root_path());
843 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
845 cerr << "actually writing state to " << tmp_path << endl;
847 if (!tree.write (tmp_path)) {
848 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
849 if (g_remove (tmp_path.c_str()) != 0) {
850 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
851 tmp_path, g_strerror (errno)) << endmsg;
857 cerr << "renaming state to " << xml_path << endl;
859 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
860 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
861 tmp_path, xml_path, g_strerror(errno)) << endmsg;
862 if (g_remove (tmp_path.c_str()) != 0) {
863 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
864 tmp_path, g_strerror (errno)) << endmsg;
872 save_history (snapshot_name);
875 bool was_dirty = dirty();
877 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
880 DirtyChanged (); /* EMIT SIGNAL */
884 StateSaved (snapshot_name); /* EMIT SIGNAL */
888 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
889 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
895 Session::restore_state (string snapshot_name)
898 if (load_state (snapshot_name) == 0) {
899 set_state (*state_tree->root(), Stateful::loading_state_version);
903 // unknown_enumeration
911 Session::load_state (string snapshot_name)
916 state_was_pending = false;
918 /* check for leftover pending state from a crashed capture attempt */
920 std::string xmlpath(_session_dir->root_path());
921 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
923 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
925 /* there is pending state from a crashed capture attempt */
927 boost::optional<int> r = AskAboutPendingState();
928 if (r.get_value_or (1)) {
929 state_was_pending = true;
933 if (!state_was_pending) {
934 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
937 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
938 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
939 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
940 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
945 state_tree = new XMLTree;
949 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
951 if (!state_tree->read (xmlpath)) {
952 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
958 XMLNode const & root (*state_tree->root());
960 if (root.name() != X_("Session")) {
961 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
968 root.get_property ("version", version);
969 Stateful::loading_state_version = parse_stateful_loading_version (version);
971 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
972 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
973 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
976 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
978 std::string backup_path(_session_dir->root_path());
979 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
980 backup_path = Glib::build_filename (backup_path, backup_filename);
982 // only create a backup for a given statefile version once
984 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
986 VersionMismatch (xmlpath, backup_path);
988 if (!copy_file (xmlpath, backup_path)) {;
994 save_snapshot_name (snapshot_name);
1000 Session::load_options (const XMLNode& node)
1002 config.set_variables (node);
1007 Session::save_default_options ()
1009 return config.save_state();
1013 Session::get_state()
1019 Session::get_template()
1021 /* if we don't disable rec-enable, diskstreams
1022 will believe they need to store their capture
1023 sources in their state node.
1026 disable_record (false);
1028 return state(false);
1031 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1032 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1035 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1037 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1040 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1044 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1047 XMLNode* node = new XMLNode("TrackState"); // XXX
1050 PlaylistSet playlists; // SessionPlaylists
1053 // these will work with new_route_from_template()
1054 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1055 child = node->add_child ("Routes");
1056 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1057 if ((*i)->is_auditioner()) {
1060 if ((*i)->is_master() || (*i)->is_monitor()) {
1063 child->add_child_nocopy ((*i)->get_state());
1064 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1066 playlists.insert (track->playlist ());
1070 // on load, Regions in the playlists need to resolve and map Source-IDs
1071 // also playlist needs to be merged or created with new-name..
1072 // ... and Diskstream in tracks adjusted to use the correct playlist
1073 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1074 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1075 child->add_child_nocopy ((*i)->get_state ());
1076 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1077 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1078 const Region::SourceList& sl = (*s)->sources ();
1079 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1080 sources.insert (*sli);
1085 child = node->add_child ("Sources");
1086 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1087 child->add_child_nocopy ((*i)->get_state ());
1088 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1090 #ifdef PLATFORM_WINDOWS
1093 string p = fs->path ();
1094 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1098 std::string sn = Glib::build_filename (path, "share.axml");
1101 tree.set_root (node);
1102 return tree.write (sn.c_str());
1107 struct route_id_compare {
1109 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1111 return r1->id () < r2->id ();
1117 Session::state (bool full_state, snapshot_t snapshot_type)
1120 XMLNode* node = new XMLNode("Session");
1123 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1125 child = node->add_child ("ProgramVersion");
1126 child->set_property("created-with", created_with);
1128 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1129 child->set_property("modified-with", modified_with);
1131 /* store configuration settings */
1135 node->set_property ("name", _name);
1136 node->set_property ("sample-rate", _base_frame_rate);
1138 if (session_dirs.size() > 1) {
1142 vector<space_and_path>::iterator i = session_dirs.begin();
1143 vector<space_and_path>::iterator next;
1145 ++i; /* skip the first one */
1149 while (i != session_dirs.end()) {
1153 if (next != session_dirs.end()) {
1154 p += G_SEARCHPATH_SEPARATOR;
1163 child = node->add_child ("Path");
1164 child->add_content (p);
1166 node->set_property ("end-is-free", _session_range_end_is_free);
1169 /* save the ID counter */
1171 node->set_property ("id-counter", ID::counter());
1173 node->set_property ("name-counter", name_id_counter ());
1175 /* save the event ID counter */
1177 node->set_property ("event-counter", Evoral::event_id_counter());
1179 /* save the VCA counter */
1181 node->set_property ("vca-counter", VCA::get_next_vca_number());
1183 /* various options */
1185 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1186 if (!midi_port_nodes.empty()) {
1187 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1188 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1189 midi_port_stuff->add_child_nocopy (**n);
1191 node->add_child_nocopy (*midi_port_stuff);
1194 XMLNode& cfgxml (config.get_variables ());
1196 /* exclude search-paths from template */
1197 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1198 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1199 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1201 node->add_child_nocopy (cfgxml);
1203 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1205 child = node->add_child ("Sources");
1208 Glib::Threads::Mutex::Lock sl (source_lock);
1210 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1212 /* Don't save information about non-file Sources, or
1213 * about non-destructive file sources that are empty
1214 * and unused by any regions.
1216 boost::shared_ptr<FileSource> fs;
1218 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1222 if (!fs->destructive()) {
1223 if (fs->empty() && !fs->used()) {
1228 if (snapshot_type != NormalSave && fs->within_session ()) {
1229 /* copy MIDI sources to new file
1231 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1232 * because the GUI (midi_region) has a direct pointer to the midi-model
1233 * of the source, as does UndoTransaction.
1235 * On the upside, .mid files are not kept open. The file is only open
1236 * when reading the model initially and when flushing the model to disk:
1237 * source->session_saved () or export.
1239 * We can change the _path of the existing source under the hood, keeping
1240 * all IDs, references and pointers intact.
1242 boost::shared_ptr<SMFSource> ms;
1243 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1244 const std::string ancestor_name = ms->ancestor_name();
1245 const std::string base = PBD::basename_nosuffix(ancestor_name);
1246 const string path = new_midi_source_path (base, false);
1248 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1249 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1250 Source::Lock lm (ms->mutex());
1252 // TODO special-case empty, removable() files: just create a new removable.
1253 // (load + write flushes the model and creates the file)
1255 ms->load_model (lm);
1257 if (ms->write_to (lm, newsrc, Evoral::MinBeats, Evoral::MaxBeats)) {
1258 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1260 if (snapshot_type == SnapshotKeep) {
1261 /* keep working on current session.
1263 * Save snapshot-state with the original filename.
1264 * Switch to use new path for future saves of the main session.
1266 child->add_child_nocopy (ms->get_state());
1270 * ~SMFSource unlinks removable() files.
1272 std::string npath (ms->path ());
1273 ms->replace_file (newsrc->path ());
1274 newsrc->replace_file (npath);
1276 if (snapshot_type == SwitchToSnapshot) {
1277 /* save and switch to snapshot.
1279 * Leave the old file in place (as is).
1280 * Snapshot uses new source directly
1282 child->add_child_nocopy (ms->get_state());
1289 child->add_child_nocopy (siter->second->get_state());
1293 child = node->add_child ("Regions");
1296 Glib::Threads::Mutex::Lock rl (region_lock);
1297 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1298 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1299 boost::shared_ptr<Region> r = i->second;
1300 /* only store regions not attached to playlists */
1301 if (r->playlist() == 0) {
1302 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1303 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1305 child->add_child_nocopy (r->get_state ());
1310 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1312 if (!cassocs.empty()) {
1313 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1315 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1316 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1317 can->set_property (X_("copy"), i->first->id());
1318 can->set_property (X_("original"), i->second->id());
1319 ca->add_child_nocopy (*can);
1326 node->add_child_nocopy (_selection->get_state());
1329 node->add_child_nocopy (_locations->get_state());
1332 Locations loc (*this);
1333 const bool was_dirty = dirty();
1334 // for a template, just create a new Locations, populate it
1335 // with the default start and end, and get the state for that.
1336 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1337 range->set (max_framepos, 0);
1339 XMLNode& locations_state = loc.get_state();
1341 if (ARDOUR::Profile->get_trx() && _locations) {
1342 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1343 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1344 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1345 locations_state.add_child_nocopy ((*i)->get_state ());
1349 node->add_child_nocopy (locations_state);
1351 /* adding a location above will have marked the session
1352 * dirty. This is an artifact, so fix it if the session wasn't
1357 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1361 child = node->add_child ("Bundles");
1363 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1364 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1365 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1367 child->add_child_nocopy (b->get_state());
1372 node->add_child_nocopy (_vca_manager->get_state());
1374 child = node->add_child ("Routes");
1376 boost::shared_ptr<RouteList> r = routes.reader ();
1378 route_id_compare cmp;
1379 RouteList xml_node_order (*r);
1380 xml_node_order.sort (cmp);
1382 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1383 if (!(*i)->is_auditioner()) {
1385 child->add_child_nocopy ((*i)->get_state());
1387 child->add_child_nocopy ((*i)->get_template());
1393 playlists->add_state (node, full_state);
1395 child = node->add_child ("RouteGroups");
1396 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1397 child->add_child_nocopy ((*i)->get_state());
1401 XMLNode* gain_child = node->add_child ("Click");
1402 gain_child->add_child_nocopy (_click_io->state (full_state));
1403 gain_child->add_child_nocopy (_click_gain->state (full_state));
1407 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1408 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1412 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1413 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1416 node->add_child_nocopy (_speakers->get_state());
1417 node->add_child_nocopy (_tempo_map->get_state());
1418 node->add_child_nocopy (get_control_protocol_state());
1421 node->add_child_copy (*_extra_xml);
1425 Glib::Threads::Mutex::Lock lm (lua_lock);
1428 luabridge::LuaRef savedstate ((*_lua_save)());
1429 saved = savedstate.cast<std::string>();
1431 lua.collect_garbage ();
1434 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1435 std::string b64s (b64);
1438 XMLNode* script_node = new XMLNode (X_("Script"));
1439 script_node->set_property (X_("lua"), LUA_VERSION);
1440 script_node->add_content (b64s);
1441 node->add_child_nocopy (*script_node);
1448 Session::get_control_protocol_state ()
1450 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1451 return cpm.get_state();
1455 Session::set_state (const XMLNode& node, int version)
1462 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1464 if (node.name() != X_("Session")) {
1465 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1469 node.get_property ("name", _name);
1471 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1473 _nominal_frame_rate = _base_frame_rate;
1475 assert (AudioEngine::instance()->running ());
1476 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1477 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1478 if (r.get_value_or (0)) {
1484 created_with = "unknown";
1485 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1486 child->get_property (X_("created-with"), created_with);
1489 setup_raid_path(_session_dir->root_path());
1491 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1494 if (node.get_property (X_("id-counter"), counter)) {
1495 ID::init_counter (counter);
1497 /* old sessions used a timebased counter, so fake
1498 * the startup ID counter based on a standard
1503 ID::init_counter (now);
1506 if (node.get_property (X_("name-counter"), counter)) {
1507 init_name_id_counter (counter);
1510 if (node.get_property (X_("event-counter"), counter)) {
1511 Evoral::init_event_id_counter (counter);
1514 if (node.get_property (X_("vca-counter"), counter)) {
1515 VCA::set_next_vca_number (counter);
1517 VCA::set_next_vca_number (1);
1520 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1521 _midi_ports->set_midi_port_states (child->children());
1524 IO::disable_connecting ();
1526 Stateful::save_extra_xml (node);
1528 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1529 load_options (*child);
1530 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1531 load_options (*child);
1533 error << _("Session: XML state has no options section") << endmsg;
1536 if (version >= 3000) {
1537 if ((child = find_named_node (node, "Metadata")) == 0) {
1538 warning << _("Session: XML state has no metadata section") << endmsg;
1539 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1544 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1545 _speakers->set_state (*child, version);
1548 if ((child = find_named_node (node, "Sources")) == 0) {
1549 error << _("Session: XML state has no sources section") << endmsg;
1551 } else if (load_sources (*child)) {
1555 if ((child = find_named_node (node, "TempoMap")) == 0) {
1556 error << _("Session: XML state has no Tempo Map section") << endmsg;
1558 } else if (_tempo_map->set_state (*child, version)) {
1562 if ((child = find_named_node (node, "Locations")) == 0) {
1563 error << _("Session: XML state has no locations section") << endmsg;
1565 } else if (_locations->set_state (*child, version)) {
1569 locations_changed ();
1571 if (_session_range_location) {
1572 AudioFileSource::set_header_position_offset (_session_range_location->start());
1575 if ((child = find_named_node (node, "Regions")) == 0) {
1576 error << _("Session: XML state has no Regions section") << endmsg;
1578 } else if (load_regions (*child)) {
1582 if ((child = find_named_node (node, "Playlists")) == 0) {
1583 error << _("Session: XML state has no playlists section") << endmsg;
1585 } else if (playlists->load (*this, *child)) {
1589 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1591 } else if (playlists->load_unused (*this, *child)) {
1595 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1596 if (load_compounds (*child)) {
1601 if (version >= 3000) {
1602 if ((child = find_named_node (node, "Bundles")) == 0) {
1603 warning << _("Session: XML state has no bundles section") << endmsg;
1606 /* We can't load Bundles yet as they need to be able
1607 * to convert from port names to Port objects, which can't happen until
1609 _bundle_xml_node = new XMLNode (*child);
1613 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1614 _vca_manager->set_state (*child, version);
1617 if ((child = find_named_node (node, "Routes")) == 0) {
1618 error << _("Session: XML state has no routes section") << endmsg;
1620 } else if (load_routes (*child, version)) {
1624 /* Now that we have Routes and masters loaded, connect them if appropriate */
1626 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1628 if (version >= 3000) {
1630 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1631 error << _("Session: XML state has no route groups section") << endmsg;
1633 } else if (load_route_groups (*child, version)) {
1637 } else if (version < 3000) {
1639 if ((child = find_named_node (node, "EditGroups")) == 0) {
1640 error << _("Session: XML state has no edit groups section") << endmsg;
1642 } else if (load_route_groups (*child, version)) {
1646 if ((child = find_named_node (node, "MixGroups")) == 0) {
1647 error << _("Session: XML state has no mix groups section") << endmsg;
1649 } else if (load_route_groups (*child, version)) {
1654 if ((child = find_named_node (node, "Click")) == 0) {
1655 warning << _("Session: XML state has no click section") << endmsg;
1656 } else if (_click_io) {
1657 setup_click_state (&node);
1660 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1661 ControlProtocolManager::instance().set_state (*child, version);
1664 if ((child = find_named_node (node, "Script"))) {
1665 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1666 if (!(*n)->is_content ()) { continue; }
1668 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1670 Glib::Threads::Mutex::Lock lm (lua_lock);
1671 (*_lua_load)(std::string ((const char*)buf, size));
1672 } catch (luabridge::LuaException const& e) {
1673 cerr << "LuaException:" << e.what () << endl;
1679 if ((child = find_named_node (node, X_("Selection")))) {
1680 _selection->set_state (*child, version);
1683 update_route_record_state ();
1685 /* here beginneth the second phase ... */
1686 set_snapshot_name (_current_snapshot_name);
1688 StateReady (); /* EMIT SIGNAL */
1701 Session::load_routes (const XMLNode& node, int version)
1704 XMLNodeConstIterator niter;
1705 RouteList new_routes;
1707 nlist = node.children();
1711 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1713 boost::shared_ptr<Route> route;
1714 if (version < 3000) {
1715 route = XMLRouteFactory_2X (**niter, version);
1717 route = XMLRouteFactory (**niter, version);
1721 error << _("Session: cannot create Route from XML description.") << endmsg;
1725 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1727 new_routes.push_back (route);
1730 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1732 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1734 BootMessage (_("Finished adding tracks/busses"));
1739 boost::shared_ptr<Route>
1740 Session::XMLRouteFactory (const XMLNode& node, int version)
1742 boost::shared_ptr<Route> ret;
1744 if (node.name() != "Route") {
1748 XMLNode* pl_child = find_named_node (node, X_("audio-playlist"));
1751 pl_child = find_named_node (node, X_("midi-playlist"));
1754 DataType type = DataType::AUDIO;
1755 node.get_property("default-type", type);
1757 assert (type != DataType::NIL);
1761 boost::shared_ptr<Track> track;
1763 if (type == DataType::AUDIO) {
1764 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1766 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1769 if (track->init()) {
1773 if (track->set_state (node, version)) {
1777 BOOST_MARK_TRACK (track);
1781 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1782 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1784 if (r->init () == 0 && r->set_state (node, version) == 0) {
1785 BOOST_MARK_ROUTE (r);
1793 boost::shared_ptr<Route>
1794 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1796 boost::shared_ptr<Route> ret;
1798 if (node.name() != "Route") {
1802 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1804 ds_prop = node.property (X_("diskstream"));
1807 DataType type = DataType::AUDIO;
1808 node.get_property("default-type", type);
1810 assert (type != DataType::NIL);
1814 // XXX DISK .... how to load 2.x diskstreams ?
1816 error << _("Could not find diskstream for route") << endmsg;
1817 return boost::shared_ptr<Route> ();
1819 boost::shared_ptr<Track> track;
1821 if (type == DataType::AUDIO) {
1822 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1824 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1827 if (track->init()) {
1831 if (track->set_state (node, version)) {
1835 // XXX DISK NEED TO SET UP DISKSTREAM ???
1837 BOOST_MARK_TRACK (track);
1841 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1842 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1844 if (r->init () == 0 && r->set_state (node, version) == 0) {
1845 BOOST_MARK_ROUTE (r);
1854 Session::load_regions (const XMLNode& node)
1857 XMLNodeConstIterator niter;
1858 boost::shared_ptr<Region> region;
1860 nlist = node.children();
1864 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1865 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1866 error << _("Session: cannot create Region from XML description.");
1867 XMLProperty const * name = (**niter).property("name");
1870 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1881 Session::load_compounds (const XMLNode& node)
1883 XMLNodeList calist = node.children();
1884 XMLNodeConstIterator caiter;
1885 XMLProperty const * caprop;
1887 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1888 XMLNode* ca = *caiter;
1892 if ((caprop = ca->property (X_("original"))) == 0) {
1895 orig_id = caprop->value();
1897 if ((caprop = ca->property (X_("copy"))) == 0) {
1900 copy_id = caprop->value();
1902 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1903 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1905 if (!orig || !copy) {
1906 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1912 RegionFactory::add_compound_association (orig, copy);
1919 Session::load_nested_sources (const XMLNode& node)
1922 XMLNodeConstIterator niter;
1924 nlist = node.children();
1926 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1927 if ((*niter)->name() == "Source") {
1929 /* it may already exist, so don't recreate it unnecessarily
1932 XMLProperty const * prop = (*niter)->property (X_("id"));
1934 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1938 ID source_id (prop->value());
1940 if (!source_by_id (source_id)) {
1943 SourceFactory::create (*this, **niter, true);
1945 catch (failed_constructor& err) {
1946 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1953 boost::shared_ptr<Region>
1954 Session::XMLRegionFactory (const XMLNode& node, bool full)
1956 XMLProperty const * type = node.property("type");
1960 const XMLNodeList& nlist = node.children();
1962 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1963 XMLNode *child = (*niter);
1964 if (child->name() == "NestedSource") {
1965 load_nested_sources (*child);
1969 if (!type || type->value() == "audio") {
1970 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1971 } else if (type->value() == "midi") {
1972 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1975 } catch (failed_constructor& err) {
1976 return boost::shared_ptr<Region> ();
1979 return boost::shared_ptr<Region> ();
1982 boost::shared_ptr<AudioRegion>
1983 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1985 XMLProperty const * prop;
1986 boost::shared_ptr<Source> source;
1987 boost::shared_ptr<AudioSource> as;
1989 SourceList master_sources;
1990 uint32_t nchans = 1;
1993 if (node.name() != X_("Region")) {
1994 return boost::shared_ptr<AudioRegion>();
1997 node.get_property (X_("channels"), nchans);
1999 if ((prop = node.property ("name")) == 0) {
2000 cerr << "no name for this region\n";
2004 if ((prop = node.property (X_("source-0"))) == 0) {
2005 if ((prop = node.property ("source")) == 0) {
2006 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2007 return boost::shared_ptr<AudioRegion>();
2011 PBD::ID s_id (prop->value());
2013 if ((source = source_by_id (s_id)) == 0) {
2014 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2015 return boost::shared_ptr<AudioRegion>();
2018 as = boost::dynamic_pointer_cast<AudioSource>(source);
2020 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2021 return boost::shared_ptr<AudioRegion>();
2024 sources.push_back (as);
2026 /* pickup other channels */
2028 for (uint32_t n=1; n < nchans; ++n) {
2029 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2030 if ((prop = node.property (buf)) != 0) {
2032 PBD::ID id2 (prop->value());
2034 if ((source = source_by_id (id2)) == 0) {
2035 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2036 return boost::shared_ptr<AudioRegion>();
2039 as = boost::dynamic_pointer_cast<AudioSource>(source);
2041 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2042 return boost::shared_ptr<AudioRegion>();
2044 sources.push_back (as);
2048 for (uint32_t n = 0; n < nchans; ++n) {
2049 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2050 if ((prop = node.property (buf)) != 0) {
2052 PBD::ID id2 (prop->value());
2054 if ((source = source_by_id (id2)) == 0) {
2055 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2056 return boost::shared_ptr<AudioRegion>();
2059 as = boost::dynamic_pointer_cast<AudioSource>(source);
2061 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2062 return boost::shared_ptr<AudioRegion>();
2064 master_sources.push_back (as);
2069 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2071 /* a final detail: this is the one and only place that we know how long missing files are */
2073 if (region->whole_file()) {
2074 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2075 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2077 sfp->set_length (region->length());
2082 if (!master_sources.empty()) {
2083 if (master_sources.size() != nchans) {
2084 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2086 region->set_master_sources (master_sources);
2094 catch (failed_constructor& err) {
2095 return boost::shared_ptr<AudioRegion>();
2099 boost::shared_ptr<MidiRegion>
2100 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2102 XMLProperty const * prop;
2103 boost::shared_ptr<Source> source;
2104 boost::shared_ptr<MidiSource> ms;
2107 if (node.name() != X_("Region")) {
2108 return boost::shared_ptr<MidiRegion>();
2111 if ((prop = node.property ("name")) == 0) {
2112 cerr << "no name for this region\n";
2116 if ((prop = node.property (X_("source-0"))) == 0) {
2117 if ((prop = node.property ("source")) == 0) {
2118 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2119 return boost::shared_ptr<MidiRegion>();
2123 PBD::ID s_id (prop->value());
2125 if ((source = source_by_id (s_id)) == 0) {
2126 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2127 return boost::shared_ptr<MidiRegion>();
2130 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2132 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2133 return boost::shared_ptr<MidiRegion>();
2136 sources.push_back (ms);
2139 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2140 /* a final detail: this is the one and only place that we know how long missing files are */
2142 if (region->whole_file()) {
2143 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2144 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2146 sfp->set_length (region->length());
2154 catch (failed_constructor& err) {
2155 return boost::shared_ptr<MidiRegion>();
2160 Session::get_sources_as_xml ()
2163 XMLNode* node = new XMLNode (X_("Sources"));
2164 Glib::Threads::Mutex::Lock lm (source_lock);
2166 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2167 node->add_child_nocopy (i->second->get_state());
2174 Session::reset_write_sources (bool mark_write_complete, bool force)
2176 boost::shared_ptr<RouteList> rl = routes.reader();
2177 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2178 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2180 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2181 tr->reset_write_sources(mark_write_complete, force);
2182 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2188 Session::load_sources (const XMLNode& node)
2191 XMLNodeConstIterator niter;
2192 /* don't need this but it stops some
2193 * versions of gcc complaining about
2194 * discarded return values.
2196 boost::shared_ptr<Source> source;
2198 nlist = node.children();
2201 std::map<std::string, std::string> relocation;
2203 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2204 #ifdef PLATFORM_WINDOWS
2208 XMLNode srcnode (**niter);
2209 bool try_replace_abspath = true;
2213 #ifdef PLATFORM_WINDOWS
2214 // do not show "insert media" popups (files embedded from removable media).
2215 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2217 if ((source = XMLSourceFactory (srcnode)) == 0) {
2218 error << _("Session: cannot create Source from XML description.") << endmsg;
2220 #ifdef PLATFORM_WINDOWS
2221 SetErrorMode(old_mode);
2224 } catch (MissingSource& err) {
2225 #ifdef PLATFORM_WINDOWS
2226 SetErrorMode(old_mode);
2229 /* try previous abs path replacements first */
2230 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2231 std::string dir = Glib::path_get_dirname (err.path);
2232 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2233 if (rl != relocation.end ()) {
2234 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2235 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2236 srcnode.set_property ("origin", newpath);
2237 try_replace_abspath = false;
2244 _missing_file_replacement = "";
2246 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2247 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2248 PROGRAM_NAME) << endmsg;
2252 if (!no_questions_about_missing_files) {
2253 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2258 switch (user_choice) {
2260 /* user added a new search location
2261 * or selected a new absolute path,
2263 if (Glib::path_is_absolute (err.path)) {
2264 if (!_missing_file_replacement.empty ()) {
2265 /* replace origin, in XML */
2266 std::string newpath = Glib::build_filename (
2267 _missing_file_replacement, Glib::path_get_basename (err.path));
2268 srcnode.set_property ("origin", newpath);
2269 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2270 _missing_file_replacement = "";
2277 /* user asked to quit the entire session load */
2281 no_questions_about_missing_files = true;
2285 no_questions_about_missing_files = true;
2292 case DataType::AUDIO:
2293 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2296 case DataType::MIDI:
2297 /* The MIDI file is actually missing so
2298 * just create a new one in the same
2299 * location. Do not announce its
2303 if (!Glib::path_is_absolute (err.path)) {
2304 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2306 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2311 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2312 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2313 /* reset ID to match the missing one */
2314 source->set_id (**niter);
2315 /* Now we can announce it */
2316 SourceFactory::SourceCreated (source);
2327 boost::shared_ptr<Source>
2328 Session::XMLSourceFactory (const XMLNode& node)
2330 if (node.name() != "Source") {
2331 return boost::shared_ptr<Source>();
2335 /* note: do peak building in another thread when loading session state */
2336 return SourceFactory::create (*this, node, true);
2339 catch (failed_constructor& err) {
2340 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2341 return boost::shared_ptr<Source>();
2346 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2348 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2352 bool absolute_path = Glib::path_is_absolute (template_name);
2354 /* directory to put the template in */
2355 std::string template_dir_path;
2357 if (!absolute_path) {
2358 std::string user_template_dir(user_template_directory());
2360 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2361 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2362 user_template_dir, g_strerror (errno)) << endmsg;
2366 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2368 template_dir_path = template_name;
2371 if (!ARDOUR::Profile->get_trx()) {
2372 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2373 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2374 template_dir_path) << endmsg;
2378 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2379 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2380 template_dir_path, g_strerror (errno)) << endmsg;
2386 std::string template_file_path;
2388 if (ARDOUR::Profile->get_trx()) {
2389 template_file_path = template_name;
2391 if (absolute_path) {
2392 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2394 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2398 SessionSaveUnderway (); /* EMIT SIGNAL */
2403 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2404 root = &get_template ();
2407 root->remove_nodes_and_delete (X_("description"));
2409 if (!description.empty()) {
2410 XMLNode* desc = new XMLNode (X_("description"));
2411 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2412 desc->add_child_nocopy (*desc_cont);
2414 root->add_child_nocopy (*desc);
2417 tree.set_root (root);
2419 if (!tree.write (template_file_path)) {
2420 error << _("template not saved") << endmsg;
2424 store_recent_templates (template_file_path);
2430 Session::refresh_disk_space ()
2432 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2434 Glib::Threads::Mutex::Lock lm (space_lock);
2436 /* get freespace on every FS that is part of the session path */
2438 _total_free_4k_blocks = 0;
2439 _total_free_4k_blocks_uncertain = false;
2441 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2442 #if defined(__NetBSD__)
2443 struct statvfs statfsbuf;
2445 statvfs (i->path.c_str(), &statfsbuf);
2447 struct statfs statfsbuf;
2449 statfs (i->path.c_str(), &statfsbuf);
2451 double const scale = statfsbuf.f_bsize / 4096.0;
2453 /* See if this filesystem is read-only */
2454 struct statvfs statvfsbuf;
2455 statvfs (i->path.c_str(), &statvfsbuf);
2457 /* f_bavail can be 0 if it is undefined for whatever
2458 filesystem we are looking at; Samba shares mounted
2459 via GVFS are an example of this.
2461 if (statfsbuf.f_bavail == 0) {
2462 /* block count unknown */
2464 i->blocks_unknown = true;
2465 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2466 /* read-only filesystem */
2468 i->blocks_unknown = false;
2470 /* read/write filesystem with known space */
2471 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2472 i->blocks_unknown = false;
2475 _total_free_4k_blocks += i->blocks;
2476 if (i->blocks_unknown) {
2477 _total_free_4k_blocks_uncertain = true;
2480 #elif defined PLATFORM_WINDOWS
2481 vector<string> scanned_volumes;
2482 vector<string>::iterator j;
2483 vector<space_and_path>::iterator i;
2484 DWORD nSectorsPerCluster, nBytesPerSector,
2485 nFreeClusters, nTotalClusters;
2489 _total_free_4k_blocks = 0;
2491 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2492 strncpy (disk_drive, (*i).path.c_str(), 3);
2496 volume_found = false;
2497 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2499 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2500 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2501 i->blocks = (uint32_t)(nFreeBytes / 4096);
2503 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2504 if (0 == j->compare(disk_drive)) {
2505 volume_found = true;
2510 if (!volume_found) {
2511 scanned_volumes.push_back(disk_drive);
2512 _total_free_4k_blocks += i->blocks;
2517 if (0 == _total_free_4k_blocks) {
2518 strncpy (disk_drive, path().c_str(), 3);
2521 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2523 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2524 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2525 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2532 Session::get_best_session_directory_for_new_audio ()
2534 vector<space_and_path>::iterator i;
2535 string result = _session_dir->root_path();
2537 /* handle common case without system calls */
2539 if (session_dirs.size() == 1) {
2543 /* OK, here's the algorithm we're following here:
2545 We want to select which directory to use for
2546 the next file source to be created. Ideally,
2547 we'd like to use a round-robin process so as to
2548 get maximum performance benefits from splitting
2549 the files across multiple disks.
2551 However, in situations without much diskspace, an
2552 RR approach may end up filling up a filesystem
2553 with new files while others still have space.
2554 Its therefore important to pay some attention to
2555 the freespace in the filesystem holding each
2556 directory as well. However, if we did that by
2557 itself, we'd keep creating new files in the file
2558 system with the most space until it was as full
2559 as all others, thus negating any performance
2560 benefits of this RAID-1 like approach.
2562 So, we use a user-configurable space threshold. If
2563 there are at least 2 filesystems with more than this
2564 much space available, we use RR selection between them.
2565 If not, then we pick the filesystem with the most space.
2567 This gets a good balance between the two
2571 refresh_disk_space ();
2573 int free_enough = 0;
2575 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2576 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2581 if (free_enough >= 2) {
2582 /* use RR selection process, ensuring that the one
2586 i = last_rr_session_dir;
2589 if (++i == session_dirs.end()) {
2590 i = session_dirs.begin();
2593 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2594 SessionDirectory sdir(i->path);
2595 if (sdir.create ()) {
2597 last_rr_session_dir = i;
2602 } while (i != last_rr_session_dir);
2606 /* pick FS with the most freespace (and that
2607 seems to actually work ...)
2610 vector<space_and_path> sorted;
2611 space_and_path_ascending_cmp cmp;
2613 sorted = session_dirs;
2614 sort (sorted.begin(), sorted.end(), cmp);
2616 for (i = sorted.begin(); i != sorted.end(); ++i) {
2617 SessionDirectory sdir(i->path);
2618 if (sdir.create ()) {
2620 last_rr_session_dir = i;
2630 Session::automation_dir () const
2632 return Glib::build_filename (_path, automation_dir_name);
2636 Session::analysis_dir () const
2638 return Glib::build_filename (_path, analysis_dir_name);
2642 Session::plugins_dir () const
2644 return Glib::build_filename (_path, plugins_dir_name);
2648 Session::externals_dir () const
2650 return Glib::build_filename (_path, externals_dir_name);
2654 Session::load_bundles (XMLNode const & node)
2656 XMLNodeList nlist = node.children();
2657 XMLNodeConstIterator niter;
2661 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2662 if ((*niter)->name() == "InputBundle") {
2663 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2664 } else if ((*niter)->name() == "OutputBundle") {
2665 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2667 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2676 Session::load_route_groups (const XMLNode& node, int version)
2678 XMLNodeList nlist = node.children();
2679 XMLNodeConstIterator niter;
2683 if (version >= 3000) {
2685 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2686 if ((*niter)->name() == "RouteGroup") {
2687 RouteGroup* rg = new RouteGroup (*this, "");
2688 add_route_group (rg);
2689 rg->set_state (**niter, version);
2693 } else if (version < 3000) {
2695 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2696 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2697 RouteGroup* rg = new RouteGroup (*this, "");
2698 add_route_group (rg);
2699 rg->set_state (**niter, version);
2708 state_file_filter (const string &str, void* /*arg*/)
2710 return (str.length() > strlen(statefile_suffix) &&
2711 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2715 remove_end(string state)
2717 string statename(state);
2719 string::size_type start,end;
2720 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2721 statename = statename.substr (start+1);
2724 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2725 end = statename.length();
2728 return string(statename.substr (0, end));
2732 Session::possible_states (string path)
2734 vector<string> states;
2735 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2737 transform(states.begin(), states.end(), states.begin(), remove_end);
2739 sort (states.begin(), states.end());
2745 Session::possible_states () const
2747 return possible_states(_path);
2751 Session::new_route_group (const std::string& name)
2753 RouteGroup* rg = NULL;
2755 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2756 if ((*i)->name () == name) {
2763 rg = new RouteGroup (*this, name);
2764 add_route_group (rg);
2770 Session::add_route_group (RouteGroup* g)
2772 _route_groups.push_back (g);
2773 route_group_added (g); /* EMIT SIGNAL */
2775 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2776 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2777 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2783 Session::remove_route_group (RouteGroup& rg)
2785 list<RouteGroup*>::iterator i;
2787 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2788 _route_groups.erase (i);
2791 route_group_removed (); /* EMIT SIGNAL */
2795 /** Set a new order for our route groups, without adding or removing any.
2796 * @param groups Route group list in the new order.
2799 Session::reorder_route_groups (list<RouteGroup*> groups)
2801 _route_groups = groups;
2803 route_groups_reordered (); /* EMIT SIGNAL */
2809 Session::route_group_by_name (string name)
2811 list<RouteGroup *>::iterator i;
2813 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2814 if ((*i)->name() == name) {
2822 Session::all_route_group() const
2824 return *_all_route_group;
2828 Session::add_commands (vector<Command*> const & cmds)
2830 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2836 Session::add_command (Command* const cmd)
2838 assert (_current_trans);
2839 DEBUG_UNDO_HISTORY (
2840 string_compose ("Current Undo Transaction %1, adding command: %2",
2841 _current_trans->name (),
2843 _current_trans->add_command (cmd);
2846 PBD::StatefulDiffCommand*
2847 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2849 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2855 Session::begin_reversible_command (const string& name)
2857 begin_reversible_command (g_quark_from_string (name.c_str ()));
2860 /** Begin a reversible command using a GQuark to identify it.
2861 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2862 * but there must be as many begin...()s as there are commit...()s.
2865 Session::begin_reversible_command (GQuark q)
2867 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2868 to hold all the commands that are committed. This keeps the order of
2869 commands correct in the history.
2872 if (_current_trans == 0) {
2873 DEBUG_UNDO_HISTORY (string_compose (
2874 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2876 /* start a new transaction */
2877 assert (_current_trans_quarks.empty ());
2878 _current_trans = new UndoTransaction();
2879 _current_trans->set_name (g_quark_to_string (q));
2881 DEBUG_UNDO_HISTORY (
2882 string_compose ("Begin Reversible Command, current transaction: %1",
2883 _current_trans->name ()));
2886 _current_trans_quarks.push_front (q);
2890 Session::abort_reversible_command ()
2892 if (_current_trans != 0) {
2893 DEBUG_UNDO_HISTORY (
2894 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2895 _current_trans->clear();
2896 delete _current_trans;
2898 _current_trans_quarks.clear();
2903 Session::commit_reversible_command (Command *cmd)
2905 assert (_current_trans);
2906 assert (!_current_trans_quarks.empty ());
2911 DEBUG_UNDO_HISTORY (
2912 string_compose ("Current Undo Transaction %1, adding command: %2",
2913 _current_trans->name (),
2915 _current_trans->add_command (cmd);
2918 DEBUG_UNDO_HISTORY (
2919 string_compose ("Commit Reversible Command, current transaction: %1",
2920 _current_trans->name ()));
2922 _current_trans_quarks.pop_front ();
2924 if (!_current_trans_quarks.empty ()) {
2925 DEBUG_UNDO_HISTORY (
2926 string_compose ("Commit Reversible Command, transaction is not "
2927 "top-level, current transaction: %1",
2928 _current_trans->name ()));
2929 /* the transaction we're committing is not the top-level one */
2933 if (_current_trans->empty()) {
2934 /* no commands were added to the transaction, so just get rid of it */
2935 DEBUG_UNDO_HISTORY (
2936 string_compose ("Commit Reversible Command, No commands were "
2937 "added to current transaction: %1",
2938 _current_trans->name ()));
2939 delete _current_trans;
2944 gettimeofday (&now, 0);
2945 _current_trans->set_timestamp (now);
2947 _history.add (_current_trans);
2952 accept_all_audio_files (const string& path, void* /*arg*/)
2954 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2958 if (!AudioFileSource::safe_audio_file_extension (path)) {
2966 accept_all_midi_files (const string& path, void* /*arg*/)
2968 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2972 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
2973 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
2974 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2978 accept_all_state_files (const string& path, void* /*arg*/)
2980 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2984 std::string const statefile_ext (statefile_suffix);
2985 if (path.length() >= statefile_ext.length()) {
2986 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2993 Session::find_all_sources (string path, set<string>& result)
2998 if (!tree.read (path)) {
3002 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3007 XMLNodeConstIterator niter;
3009 nlist = node->children();
3013 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3015 XMLProperty const * prop;
3017 if ((prop = (*niter)->property (X_("type"))) == 0) {
3021 DataType type (prop->value());
3023 if ((prop = (*niter)->property (X_("name"))) == 0) {
3027 if (Glib::path_is_absolute (prop->value())) {
3028 /* external file, ignore */
3036 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3037 result.insert (found_path);
3045 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3047 vector<string> state_files;
3049 string this_snapshot_path;
3055 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3056 ripped = ripped.substr (0, ripped.length() - 1);
3059 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3061 if (state_files.empty()) {
3066 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3067 this_snapshot_path += statefile_suffix;
3069 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3071 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3073 if (exclude_this_snapshot && *i == this_snapshot_path) {
3074 cerr << "\texcluded\n";
3079 if (find_all_sources (*i, result) < 0) {
3087 struct RegionCounter {
3088 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3089 AudioSourceList::iterator iter;
3090 boost::shared_ptr<Region> region;
3093 RegionCounter() : count (0) {}
3097 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3099 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3100 return r.get_value_or (1);
3104 Session::cleanup_regions ()
3106 bool removed = false;
3107 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3109 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3111 uint32_t used = playlists->region_use_count (i->second);
3113 if (used == 0 && !i->second->automatic ()) {
3114 boost::weak_ptr<Region> w = i->second;
3117 RegionFactory::map_remove (w);
3124 // re-check to remove parent references of compound regions
3125 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3126 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3130 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3131 if (0 == playlists->region_use_count (i->second)) {
3132 boost::weak_ptr<Region> w = i->second;
3134 RegionFactory::map_remove (w);
3141 /* dump the history list */
3148 Session::can_cleanup_peakfiles () const
3150 if (deletion_in_progress()) {
3153 if (!_writable || (_state_of_the_state & CannotSave)) {
3154 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3157 if (record_status() == Recording) {
3158 error << _("Cannot cleanup peak-files while recording") << endmsg;
3165 Session::cleanup_peakfiles ()
3167 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3172 assert (can_cleanup_peakfiles ());
3173 assert (!peaks_cleanup_in_progres());
3175 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3177 int timeout = 5000; // 5 seconds
3178 while (!SourceFactory::files_with_peaks.empty()) {
3179 Glib::usleep (1000);
3180 if (--timeout < 0) {
3181 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3182 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3187 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3188 boost::shared_ptr<AudioSource> as;
3189 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3190 as->close_peakfile();
3194 PBD::clear_directory (session_directory().peak_path());
3196 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3198 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3199 boost::shared_ptr<AudioSource> as;
3200 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3201 SourceFactory::setup_peakfile(as, true);
3208 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3210 pl->deep_sources (*all_sources);
3214 Session::cleanup_sources (CleanupReport& rep)
3216 // FIXME: needs adaptation to midi
3218 vector<boost::shared_ptr<Source> > dead_sources;
3221 vector<string> candidates;
3222 vector<string> unused;
3223 set<string> sources_used_by_all_snapshots;
3230 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3232 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3234 /* this is mostly for windows which doesn't allow file
3235 * renaming if the file is in use. But we don't special
3236 * case it because we need to know if this causes
3237 * problems, and the easiest way to notice that is to
3238 * keep it in place for all platforms.
3241 request_stop (false);
3243 _butler->wait_until_finished ();
3245 /* consider deleting all unused playlists */
3247 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3252 /* sync the "all regions" property of each playlist with its current state */
3254 playlists->sync_all_regions_with_regions ();
3256 /* find all un-used sources */
3261 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3263 SourceMap::iterator tmp;
3268 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3272 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3273 dead_sources.push_back (i->second);
3274 i->second->drop_references ();
3280 /* build a list of all the possible audio directories for the session */
3282 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3283 SessionDirectory sdir ((*i).path);
3284 asp += sdir.sound_path();
3286 audio_path += asp.to_string();
3289 /* build a list of all the possible midi directories for the session */
3291 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3292 SessionDirectory sdir ((*i).path);
3293 msp += sdir.midi_path();
3295 midi_path += msp.to_string();
3297 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3298 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3300 /* add sources from all other snapshots as "used", but don't use this
3301 snapshot because the state file on disk still references sources we
3302 may have already dropped.
3305 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3307 /* Although the region factory has a list of all regions ever created
3308 * for this session, we're only interested in regions actually in
3309 * playlists right now. So merge all playlist regions lists together.
3311 * This will include the playlists used within compound regions.
3314 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3316 /* add our current source list
3319 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3320 boost::shared_ptr<FileSource> fs;
3321 SourceMap::iterator tmp = i;
3324 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3330 /* this is mostly for windows which doesn't allow file
3331 * renaming if the file is in use. But we do not special
3332 * case it because we need to know if this causes
3333 * problems, and the easiest way to notice that is to
3334 * keep it in place for all platforms.
3339 if (!fs->is_stub()) {
3341 /* Note that we're checking a list of all
3342 * sources across all snapshots with the list
3343 * of sources used by this snapshot.
3346 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3347 /* this source is in use by this snapshot */
3348 sources_used_by_all_snapshots.insert (fs->path());
3349 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3351 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3352 /* this source is NOT in use by this snapshot */
3354 /* remove all related regions from RegionFactory master list */
3356 RegionFactory::remove_regions_using_source (i->second);
3358 /* remove from our current source list
3359 * also. We may not remove it from
3360 * disk, because it may be used by
3361 * other snapshots, but it isn't used inside this
3362 * snapshot anymore, so we don't need a
3373 /* now check each candidate source to see if it exists in the list of
3374 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3377 cerr << "Candidates: " << candidates.size() << endl;
3378 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3380 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3385 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3387 tmppath1 = canonical_path (spath);
3388 tmppath2 = canonical_path ((*i));
3390 cerr << "\t => " << tmppath2 << endl;
3392 if (tmppath1 == tmppath2) {
3399 unused.push_back (spath);
3403 cerr << "Actually unused: " << unused.size() << endl;
3405 if (unused.empty()) {
3411 /* now try to move all unused files into the "dead" directory(ies) */
3413 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3418 /* don't move the file across filesystems, just
3419 * stick it in the `dead_dir_name' directory
3420 * on whichever filesystem it was already on.
3423 if ((*x).find ("/sounds/") != string::npos) {
3425 /* old school, go up 1 level */
3427 newpath = Glib::path_get_dirname (*x); // "sounds"
3428 newpath = Glib::path_get_dirname (newpath); // "session-name"
3432 /* new school, go up 4 levels */
3434 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3435 newpath = Glib::path_get_dirname (newpath); // "session-name"
3436 newpath = Glib::path_get_dirname (newpath); // "interchange"
3437 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3440 newpath = Glib::build_filename (newpath, dead_dir_name);
3442 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3443 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3447 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3449 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3451 /* the new path already exists, try versioning */
3453 char buf[PATH_MAX+1];
3457 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3460 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3461 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3465 if (version == 999) {
3466 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3470 newpath = newpath_v;
3475 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3476 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3477 newpath, g_strerror (errno)) << endmsg;
3481 /* see if there an easy to find peakfile for this file, and remove it. */
3483 string base = Glib::path_get_basename (*x);
3484 base += "%A"; /* this is what we add for the channel suffix of all native files,
3485 * or for the first channel of embedded files. it will miss
3486 * some peakfiles for other channels
3488 string peakpath = construct_peak_filepath (base);
3490 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3491 if (::g_unlink (peakpath.c_str ()) != 0) {
3492 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3493 g_strerror (errno)) << endmsg;
3494 /* try to back out */
3495 ::g_rename (newpath.c_str (), _path.c_str ());
3500 rep.paths.push_back (*x);
3501 rep.space += statbuf.st_size;
3504 /* dump the history list */
3508 /* save state so we don't end up a session file
3509 * referring to non-existent sources.
3516 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3522 Session::cleanup_trash_sources (CleanupReport& rep)
3524 // FIXME: needs adaptation for MIDI
3526 vector<space_and_path>::iterator i;
3532 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3534 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3536 clear_directory (dead_dir, &rep.space, &rep.paths);
3543 Session::set_dirty ()
3545 /* return early if there's nothing to do */
3550 /* never mark session dirty during loading */
3551 if (_state_of_the_state & Loading) {
3555 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3556 DirtyChanged(); /* EMIT SIGNAL */
3560 Session::set_clean ()
3562 bool was_dirty = dirty();
3564 _state_of_the_state = Clean;
3567 DirtyChanged(); /* EMIT SIGNAL */
3572 Session::set_deletion_in_progress ()
3574 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3578 Session::clear_deletion_in_progress ()
3580 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3584 Session::add_controllable (boost::shared_ptr<Controllable> c)
3586 /* this adds a controllable to the list managed by the Session.
3587 this is a subset of those managed by the Controllable class
3588 itself, and represents the only ones whose state will be saved
3589 as part of the session.
3592 Glib::Threads::Mutex::Lock lm (controllables_lock);
3593 controllables.insert (c);
3596 struct null_deleter { void operator()(void const *) const {} };
3599 Session::remove_controllable (Controllable* c)
3601 if (_state_of_the_state & Deletion) {
3605 Glib::Threads::Mutex::Lock lm (controllables_lock);
3607 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3609 if (x != controllables.end()) {
3610 controllables.erase (x);
3614 boost::shared_ptr<Controllable>
3615 Session::controllable_by_id (const PBD::ID& id)
3617 Glib::Threads::Mutex::Lock lm (controllables_lock);
3619 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3620 if ((*i)->id() == id) {
3625 return boost::shared_ptr<Controllable>();
3628 boost::shared_ptr<AutomationControl>
3629 Session::automation_control_by_id (const PBD::ID& id)
3631 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3634 boost::shared_ptr<Controllable>
3635 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3637 boost::shared_ptr<Controllable> c;
3638 boost::shared_ptr<Stripable> s;
3639 boost::shared_ptr<Route> r;
3641 switch (desc.top_level_type()) {
3642 case ControllableDescriptor::NamedRoute:
3644 std::string str = desc.top_level_name();
3646 if (str == "Master" || str == "master") {
3648 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3650 } else if (str == "auditioner") {
3653 s = route_by_name (desc.top_level_name());
3659 case ControllableDescriptor::PresentationOrderRoute:
3660 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3663 case ControllableDescriptor::PresentationOrderTrack:
3664 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3667 case ControllableDescriptor::PresentationOrderBus:
3668 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3671 case ControllableDescriptor::PresentationOrderVCA:
3672 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3675 case ControllableDescriptor::SelectionCount:
3676 s = route_by_selected_count (desc.selection_id());
3684 r = boost::dynamic_pointer_cast<Route> (s);
3686 switch (desc.subtype()) {
3687 case ControllableDescriptor::Gain:
3688 c = s->gain_control ();
3691 case ControllableDescriptor::Trim:
3692 c = s->trim_control ();
3695 case ControllableDescriptor::Solo:
3696 c = s->solo_control();
3699 case ControllableDescriptor::Mute:
3700 c = s->mute_control();
3703 case ControllableDescriptor::Recenable:
3704 c = s->rec_enable_control ();
3707 case ControllableDescriptor::PanDirection:
3708 c = s->pan_azimuth_control();
3711 case ControllableDescriptor::PanWidth:
3712 c = s->pan_width_control();
3715 case ControllableDescriptor::PanElevation:
3716 c = s->pan_elevation_control();
3719 case ControllableDescriptor::Balance:
3720 /* XXX simple pan control */
3723 case ControllableDescriptor::PluginParameter:
3725 uint32_t plugin = desc.target (0);
3726 uint32_t parameter_index = desc.target (1);
3728 /* revert to zero based counting */
3734 if (parameter_index > 0) {
3742 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3745 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3746 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3751 case ControllableDescriptor::SendGain: {
3752 uint32_t send = desc.target (0);
3759 c = r->send_level_controllable (send);
3764 /* relax and return a null pointer */
3772 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3775 Stateful::add_instant_xml (node, _path);
3778 if (write_to_config) {
3779 Config->add_instant_xml (node);
3784 Session::instant_xml (const string& node_name)
3786 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3787 if (get_disable_all_loaded_plugins ()) {
3791 return Stateful::instant_xml (node_name, _path);
3795 Session::save_history (string snapshot_name)
3803 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3804 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3808 if (snapshot_name.empty()) {
3809 snapshot_name = _current_snapshot_name;
3812 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3813 const string backup_filename = history_filename + backup_suffix;
3814 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3815 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3817 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3818 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3819 error << _("could not backup old history file, current history not saved") << endmsg;
3824 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3826 if (!tree.write (xml_path))
3828 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3830 if (g_remove (xml_path.c_str()) != 0) {
3831 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3832 xml_path, g_strerror (errno)) << endmsg;
3834 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3835 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3836 backup_path, g_strerror (errno)) << endmsg;
3846 Session::restore_history (string snapshot_name)
3850 if (snapshot_name.empty()) {
3851 snapshot_name = _current_snapshot_name;
3854 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3855 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3857 info << "Loading history from " << xml_path << endmsg;
3859 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3860 info << string_compose (_("%1: no history file \"%2\" for this session."),
3861 _name, xml_path) << endmsg;
3865 if (!tree.read (xml_path)) {
3866 error << string_compose (_("Could not understand session history file \"%1\""),
3867 xml_path) << endmsg;
3874 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3877 UndoTransaction* ut = new UndoTransaction ();
3883 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3884 !t->get_property ("tv-usec", tv_usec)) {
3888 ut->set_name (name);
3892 tv.tv_usec = tv_usec;
3893 ut->set_timestamp(tv);
3895 for (XMLNodeConstIterator child_it = t->children().begin();
3896 child_it != t->children().end(); child_it++)
3898 XMLNode *n = *child_it;
3901 if (n->name() == "MementoCommand" ||
3902 n->name() == "MementoUndoCommand" ||
3903 n->name() == "MementoRedoCommand") {
3905 if ((c = memento_command_factory(n))) {
3909 } else if (n->name() == "NoteDiffCommand") {
3910 PBD::ID id (n->property("midi-source")->value());
3911 boost::shared_ptr<MidiSource> midi_source =
3912 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3914 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3916 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3919 } else if (n->name() == "SysExDiffCommand") {
3921 PBD::ID id (n->property("midi-source")->value());
3922 boost::shared_ptr<MidiSource> midi_source =
3923 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3925 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3927 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3930 } else if (n->name() == "PatchChangeDiffCommand") {
3932 PBD::ID id (n->property("midi-source")->value());
3933 boost::shared_ptr<MidiSource> midi_source =
3934 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3936 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3938 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3941 } else if (n->name() == "StatefulDiffCommand") {
3942 if ((c = stateful_diff_command_factory (n))) {
3943 ut->add_command (c);
3946 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3957 Session::config_changed (std::string p, bool ours)
3963 if (p == "seamless-loop") {
3965 } else if (p == "rf-speed") {
3967 } else if (p == "auto-loop") {
3969 } else if (p == "session-monitoring") {
3971 } else if (p == "auto-input") {
3973 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3974 /* auto-input only makes a difference if we're rolling */
3975 set_track_monitor_input_status (!config.get_auto_input());
3978 } else if (p == "punch-in") {
3982 if ((location = _locations->auto_punch_location()) != 0) {
3984 if (config.get_punch_in ()) {
3985 replace_event (SessionEvent::PunchIn, location->start());
3987 remove_event (location->start(), SessionEvent::PunchIn);
3991 } else if (p == "punch-out") {
3995 if ((location = _locations->auto_punch_location()) != 0) {
3997 if (config.get_punch_out()) {
3998 replace_event (SessionEvent::PunchOut, location->end());
4000 clear_events (SessionEvent::PunchOut);
4004 } else if (p == "edit-mode") {
4006 Glib::Threads::Mutex::Lock lm (playlists->lock);
4008 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4009 (*i)->set_edit_mode (Config->get_edit_mode ());
4012 } else if (p == "use-video-sync") {
4014 waiting_for_sync_offset = config.get_use_video_sync();
4016 } else if (p == "mmc-control") {
4018 //poke_midi_thread ();
4020 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4022 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4024 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4026 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4028 } else if (p == "midi-control") {
4030 //poke_midi_thread ();
4032 } else if (p == "raid-path") {
4034 setup_raid_path (config.get_raid_path());
4036 } else if (p == "timecode-format") {
4040 } else if (p == "video-pullup") {
4044 } else if (p == "seamless-loop") {
4046 if (play_loop && transport_rolling()) {
4047 // to reset diskstreams etc
4048 request_play_loop (true);
4051 } else if (p == "rf-speed") {
4053 cumulative_rf_motion = 0;
4056 } else if (p == "click-sound") {
4058 setup_click_sounds (1);
4060 } else if (p == "click-emphasis-sound") {
4062 setup_click_sounds (-1);
4064 } else if (p == "clicking") {
4066 if (Config->get_clicking()) {
4067 if (_click_io && click_data) { // don't require emphasis data
4074 } else if (p == "click-record-only") {
4076 _click_rec_only = Config->get_click_record_only();
4078 } else if (p == "click-gain") {
4081 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4084 } else if (p == "send-mtc") {
4086 if (Config->get_send_mtc ()) {
4087 /* mark us ready to send */
4088 next_quarter_frame_to_send = 0;
4091 } else if (p == "send-mmc") {
4093 _mmc->enable_send (Config->get_send_mmc ());
4095 } else if (p == "jack-time-master") {
4097 engine().reset_timebase ();
4099 } else if (p == "native-file-header-format") {
4101 if (!first_file_header_format_reset) {
4102 reset_native_file_format ();
4105 first_file_header_format_reset = false;
4107 } else if (p == "native-file-data-format") {
4109 if (!first_file_data_format_reset) {
4110 reset_native_file_format ();
4113 first_file_data_format_reset = false;
4115 } else if (p == "external-sync") {
4116 if (!config.get_external_sync()) {
4117 drop_sync_source ();
4119 switch_to_sync_source (Config->get_sync_source());
4121 } else if (p == "denormal-model") {
4123 } else if (p == "history-depth") {
4124 set_history_depth (Config->get_history_depth());
4125 } else if (p == "remote-model") {
4126 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4129 } else if (p == "initial-program-change") {
4131 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4134 buf[0] = MIDI::program; // channel zero by default
4135 buf[1] = (Config->get_initial_program_change() & 0x7f);
4137 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4139 } else if (p == "solo-mute-override") {
4140 // catch_up_on_solo_mute_override ();
4141 } else if (p == "listen-position" || p == "pfl-position") {
4142 listen_position_changed ();
4143 } else if (p == "solo-control-is-listen-control") {
4144 solo_control_mode_changed ();
4145 } else if (p == "solo-mute-gain") {
4146 _solo_cut_control->Changed (true, Controllable::NoGroup);
4147 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4148 last_timecode_valid = false;
4149 } else if (p == "playback-buffer-seconds") {
4150 AudioSource::allocate_working_buffers (frame_rate());
4151 } else if (p == "ltc-source-port") {
4152 reconnect_ltc_input ();
4153 } else if (p == "ltc-sink-port") {
4154 reconnect_ltc_output ();
4155 } else if (p == "timecode-generator-offset") {
4156 ltc_tx_parse_offset();
4157 } else if (p == "auto-return-target-list") {
4158 follow_playhead_priority ();
4165 Session::set_history_depth (uint32_t d)
4167 _history.set_depth (d);
4170 /** Connect things to the MMC object */
4172 Session::setup_midi_machine_control ()
4174 _mmc = new MIDI::MachineControl;
4176 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4177 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4179 if (!async_out || !async_out) {
4183 /* XXXX argh, passing raw pointers back into libmidi++ */
4185 MIDI::Port* mmc_in = async_in.get();
4186 MIDI::Port* mmc_out = async_out.get();
4188 _mmc->set_ports (mmc_in, mmc_out);
4190 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4191 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4192 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4193 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4194 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4195 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4196 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4197 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4198 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4199 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4200 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4201 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4202 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4204 /* also handle MIDI SPP because its so common */
4206 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4207 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4208 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4211 boost::shared_ptr<Controllable>
4212 Session::solo_cut_control() const
4214 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4215 * controls in Ardour that currently get presented to the user in the GUI that require
4216 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4218 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4219 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4222 return _solo_cut_control;
4226 Session::save_snapshot_name (const std::string & n)
4228 /* assure Stateful::_instant_xml is loaded
4229 * add_instant_xml() only adds to existing data and defaults
4230 * to use an empty Tree otherwise
4232 instant_xml ("LastUsedSnapshot");
4234 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4235 last_used_snapshot->set_property ("name", n);
4236 add_instant_xml (*last_used_snapshot, false);
4240 Session::set_snapshot_name (const std::string & n)
4242 _current_snapshot_name = n;
4243 save_snapshot_name (n);
4247 Session::rename (const std::string& new_name)
4249 string legal_name = legalize_for_path (new_name);
4255 string const old_sources_root = _session_dir->sources_root();
4257 if (!_writable || (_state_of_the_state & CannotSave)) {
4258 error << _("Cannot rename read-only session.") << endmsg;
4259 return 0; // don't show "messed up" warning
4261 if (record_status() == Recording) {
4262 error << _("Cannot rename session while recording") << endmsg;
4263 return 0; // don't show "messed up" warning
4266 StateProtector stp (this);
4271 * interchange subdirectory
4275 * Backup files are left unchanged and not renamed.
4278 /* Windows requires that we close all files before attempting the
4279 * rename. This works on other platforms, but isn't necessary there.
4280 * Leave it in place for all platforms though, since it may help
4281 * catch issues that could arise if the way Source files work ever
4282 * change (since most developers are not using Windows).
4285 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4286 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4292 /* pass one: not 100% safe check that the new directory names don't
4296 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4300 /* this is a stupid hack because Glib::path_get_dirname() is
4301 * lexical-only, and so passing it /a/b/c/ gives a different
4302 * result than passing it /a/b/c ...
4305 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4306 oldstr = oldstr.substr (0, oldstr.length() - 1);
4309 string base = Glib::path_get_dirname (oldstr);
4311 newstr = Glib::build_filename (base, legal_name);
4313 cerr << "Looking for " << newstr << endl;
4315 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4316 cerr << " exists\n";
4325 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4331 /* this is a stupid hack because Glib::path_get_dirname() is
4332 * lexical-only, and so passing it /a/b/c/ gives a different
4333 * result than passing it /a/b/c ...
4336 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4337 oldstr = oldstr.substr (0, oldstr.length() - 1);
4340 string base = Glib::path_get_dirname (oldstr);
4341 newstr = Glib::build_filename (base, legal_name);
4343 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4345 cerr << "Rename " << oldstr << " => " << newstr << endl;
4346 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4347 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4348 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4352 /* Reset path in "session dirs" */
4357 /* reset primary SessionDirectory object */
4360 (*_session_dir) = newstr;
4365 /* now rename directory below session_dir/interchange */
4367 string old_interchange_dir;
4368 string new_interchange_dir;
4370 /* use newstr here because we renamed the path
4371 * (folder/directory) that used to be oldstr to newstr above
4374 v.push_back (newstr);
4375 v.push_back (interchange_dir_name);
4376 v.push_back (Glib::path_get_basename (oldstr));
4378 old_interchange_dir = Glib::build_filename (v);
4381 v.push_back (newstr);
4382 v.push_back (interchange_dir_name);
4383 v.push_back (legal_name);
4385 new_interchange_dir = Glib::build_filename (v);
4387 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4389 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4390 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4391 old_interchange_dir, new_interchange_dir,
4394 error << string_compose (_("renaming %s as %2 failed (%3)"),
4395 old_interchange_dir, new_interchange_dir,
4404 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4405 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4407 cerr << "Rename " << oldstr << " => " << newstr << endl;
4409 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4410 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4411 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4417 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4419 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4420 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4422 cerr << "Rename " << oldstr << " => " << newstr << endl;
4424 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4425 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4426 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4431 /* remove old name from recent sessions */
4432 remove_recent_sessions (_path);
4435 /* update file source paths */
4437 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4438 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4440 string p = fs->path ();
4441 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4443 SourceFactory::setup_peakfile(i->second, true);
4447 set_snapshot_name (new_name);
4452 /* save state again to get everything just right */
4454 save_state (_current_snapshot_name);
4456 /* add to recent sessions */
4458 store_recent_sessions (new_name, _path);
4464 Session::parse_stateful_loading_version (const std::string& version)
4466 if (version.empty ()) {
4467 /* no version implies very old version of Ardour */
4471 if (version.find ('.') != string::npos) {
4472 /* old school version format */
4473 if (version[0] == '2') {
4479 return string_to<int32_t>(version);
4484 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4486 bool found_sr = false;
4487 bool found_data_format = false;
4488 std::string version;
4489 program_version = "";
4491 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4495 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4499 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4502 xmlFreeParserCtxt(ctxt);
4506 xmlNodePtr node = xmlDocGetRootElement(doc);
4509 xmlFreeParserCtxt(ctxt);
4514 /* sample rate & version*/
4517 for (attr = node->properties; attr; attr = attr->next) {
4518 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4519 version = std::string ((char*)attr->children->content);
4521 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4522 sample_rate = atoi ((char*)attr->children->content);
4527 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4531 node = node->children;
4532 while (node != NULL) {
4533 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4534 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4536 program_version = string ((const char*)val);
4537 size_t sep = program_version.find_first_of("-");
4538 if (sep != string::npos) {
4539 program_version = program_version.substr (0, sep);
4544 if (strcmp((const char*) node->name, "Config")) {
4548 for (node = node->children; node; node = node->next) {
4549 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4550 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4552 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4555 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4557 found_data_format = true;
4558 } catch (PBD::unknown_enumeration& e) {}
4568 xmlFreeParserCtxt(ctxt);
4571 return (found_sr && found_data_format) ? 0 : 1;
4575 Session::get_snapshot_from_instant (const std::string& session_dir)
4577 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4579 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4584 if (!tree.read (instant_xml_path)) {
4588 XMLProperty const * prop;
4589 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4590 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4591 return prop->value();
4597 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4598 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4601 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4605 SourcePathMap source_path_map;
4607 boost::shared_ptr<AudioFileSource> afs;
4612 Glib::Threads::Mutex::Lock lm (source_lock);
4614 cerr << " total sources = " << sources.size();
4616 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4617 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4623 if (fs->within_session()) {
4627 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4628 source_path_map[fs->path()].push_back (fs);
4630 SeveralFileSources v;
4632 source_path_map.insert (make_pair (fs->path(), v));
4638 cerr << " fsources = " << total << endl;
4640 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4642 /* tell caller where we are */
4644 string old_path = i->first;
4646 callback (n, total, old_path);
4648 cerr << old_path << endl;
4652 switch (i->second.front()->type()) {
4653 case DataType::AUDIO:
4654 new_path = new_audio_source_path_for_embedded (old_path);
4657 case DataType::MIDI:
4658 /* XXX not implemented yet */
4662 if (new_path.empty()) {
4666 cerr << "Move " << old_path << " => " << new_path << endl;
4668 if (!copy_file (old_path, new_path)) {
4669 cerr << "failed !\n";
4673 /* make sure we stop looking in the external
4674 dir/folder. Remember, this is an all-or-nothing
4675 operations, it doesn't merge just some files.
4677 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4679 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4680 (*f)->set_path (new_path);
4685 save_state ("", false, false);
4691 bool accept_all_files (string const &, void *)
4697 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4699 /* 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.
4704 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4706 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4708 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4710 v.push_back (new_session_folder); /* full path */
4711 v.push_back (interchange_dir_name);
4712 v.push_back (new_session_path); /* just one directory/folder */
4713 v.push_back (typedir);
4714 v.push_back (Glib::path_get_basename (old_path));
4716 return Glib::build_filename (v);
4720 Session::save_as (SaveAs& saveas)
4722 vector<string> files;
4723 string current_folder = Glib::path_get_dirname (_path);
4724 string new_folder = legalize_for_path (saveas.new_name);
4725 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4726 int64_t total_bytes = 0;
4730 int32_t internal_file_cnt = 0;
4732 vector<string> do_not_copy_extensions;
4733 do_not_copy_extensions.push_back (statefile_suffix);
4734 do_not_copy_extensions.push_back (pending_suffix);
4735 do_not_copy_extensions.push_back (backup_suffix);
4736 do_not_copy_extensions.push_back (temp_suffix);
4737 do_not_copy_extensions.push_back (history_suffix);
4739 /* get total size */
4741 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4743 /* need to clear this because
4744 * find_files_matching_filter() is cumulative
4749 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4751 all += files.size();
4753 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4755 g_stat ((*i).c_str(), &gsb);
4756 total_bytes += gsb.st_size;
4760 /* save old values so we can switch back if we are not switching to the new session */
4762 string old_path = _path;
4763 string old_name = _name;
4764 string old_snapshot = _current_snapshot_name;
4765 string old_sd = _session_dir->root_path();
4766 vector<string> old_search_path[DataType::num_types];
4767 string old_config_search_path[DataType::num_types];
4769 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4770 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4771 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4772 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4774 /* switch session directory */
4776 (*_session_dir) = to_dir;
4778 /* create new tree */
4780 if (!_session_dir->create()) {
4781 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4786 /* copy all relevant files. Find each location in session_dirs,
4787 * and copy files from there to target.
4790 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4792 /* need to clear this because
4793 * find_files_matching_filter() is cumulative
4798 const size_t prefix_len = (*sd).path.size();
4800 /* Work just on the files within this session dir */
4802 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4804 /* add dir separator to protect against collisions with
4805 * track names (e.g. track named "audiofiles" or
4809 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4810 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4811 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4813 /* copy all the files. Handling is different for media files
4814 than others because of the *silly* subtree we have below the interchange
4815 folder. That really was a bad idea, but I'm not fixing it as part of
4816 implementing ::save_as().
4819 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4821 std::string from = *i;
4824 string filename = Glib::path_get_basename (from);
4825 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4826 if (filename == ".DS_STORE") {
4831 if (from.find (audiofile_dir_string) != string::npos) {
4833 /* audio file: only copy if asked */
4835 if (saveas.include_media && saveas.copy_media) {
4837 string to = make_new_media_path (*i, to_dir, new_folder);
4839 info << "media file copying from " << from << " to " << to << endmsg;
4841 if (!copy_file (from, to)) {
4842 throw Glib::FileError (Glib::FileError::IO_ERROR,
4843 string_compose(_("\ncopying \"%1\" failed !"), from));
4847 /* we found media files inside the session folder */
4849 internal_file_cnt++;
4851 } else if (from.find (midifile_dir_string) != string::npos) {
4853 /* midi file: always copy unless
4854 * creating an empty new session
4857 if (saveas.include_media) {
4859 string to = make_new_media_path (*i, to_dir, new_folder);
4861 info << "media file copying from " << from << " to " << to << endmsg;
4863 if (!copy_file (from, to)) {
4864 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4868 /* we found media files inside the session folder */
4870 internal_file_cnt++;
4872 } else if (from.find (analysis_dir_string) != string::npos) {
4874 /* make sure analysis dir exists in
4875 * new session folder, but we're not
4876 * copying analysis files here, see
4880 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4885 /* normal non-media file. Don't copy state, history, etc.
4888 bool do_copy = true;
4890 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4891 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4892 /* end of filename matches extension, do not copy file */
4898 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4899 /* don't copy peakfiles if
4900 * we're not copying media
4906 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4908 info << "attempting to make directory/folder " << to << endmsg;
4910 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4911 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4914 info << "attempting to copy " << from << " to " << to << endmsg;
4916 if (!copy_file (from, to)) {
4917 throw Glib::FileError (Glib::FileError::IO_ERROR,
4918 string_compose(_("\ncopying \"%1\" failed !"), from));
4923 /* measure file size even if we're not going to copy so that our Progress
4924 signals are correct, since we included these do-not-copy files
4925 in the computation of the total size and file count.
4929 g_stat (from.c_str(), &gsb);
4930 copied += gsb.st_size;
4933 double fraction = (double) copied / total_bytes;
4935 bool keep_going = true;
4937 if (saveas.copy_media) {
4939 /* no need or expectation of this if
4940 * media is not being copied, because
4941 * it will be fast(ish).
4944 /* tell someone "X percent, file M of N"; M is one-based */
4946 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4954 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4960 /* copy optional folders, if any */
4962 string old = plugins_dir ();
4963 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4964 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4965 copy_files (old, newdir);
4968 old = externals_dir ();
4969 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4970 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4971 copy_files (old, newdir);
4974 old = automation_dir ();
4975 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4976 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4977 copy_files (old, newdir);
4980 if (saveas.include_media) {
4982 if (saveas.copy_media) {
4983 #ifndef PLATFORM_WINDOWS
4984 /* There are problems with analysis files on
4985 * Windows, because they used a colon in their
4986 * names as late as 4.0. Colons are not legal
4987 * under Windows even if NTFS allows them.
4989 * This is a tricky problem to solve so for
4990 * just don't copy these files. They will be
4991 * regenerated as-needed anyway, subject to the
4992 * existing issue that the filenames will be
4993 * rejected by Windows, which is a separate
4994 * problem (though related).
4997 /* only needed if we are copying media, since the
4998 * analysis data refers to media data
5001 old = analysis_dir ();
5002 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5003 string newdir = Glib::build_filename (to_dir, "analysis");
5004 copy_files (old, newdir);
5006 #endif /* PLATFORM_WINDOWS */
5011 set_snapshot_name (saveas.new_name);
5012 _name = saveas.new_name;
5014 if (saveas.include_media && !saveas.copy_media) {
5016 /* reset search paths of the new session (which we're pretending to be right now) to
5017 include the original session search path, so we can still find all audio.
5020 if (internal_file_cnt) {
5021 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5022 ensure_search_path_includes (*s, DataType::AUDIO);
5023 cerr << "be sure to include " << *s << " for audio" << endl;
5026 /* we do not do this for MIDI because we copy
5027 all MIDI files if saveas.include_media is
5033 bool was_dirty = dirty ();
5035 save_default_options ();
5037 if (saveas.copy_media && saveas.copy_external) {
5038 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5039 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5043 saveas.final_session_folder_name = _path;
5045 store_recent_sessions (_name, _path);
5047 if (!saveas.switch_to) {
5049 /* save the new state */
5051 save_state ("", false, false, !saveas.include_media);
5053 /* switch back to the way things were */
5057 set_snapshot_name (old_snapshot);
5059 (*_session_dir) = old_sd;
5065 if (internal_file_cnt) {
5066 /* reset these to their original values */
5067 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5068 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5073 /* prune session dirs, and update disk space statistics
5078 session_dirs.clear ();
5079 session_dirs.push_back (sp);
5080 refresh_disk_space ();
5082 _writable = exists_and_writable (_path);
5084 /* ensure that all existing tracks reset their current capture source paths
5086 reset_write_sources (true, true);
5088 /* creating new write sources marks the session as
5089 dirty. If the new session is empty, then
5090 save_state() thinks we're saving a template and will
5091 not mark the session as clean. So do that here,
5092 before we save state.
5095 if (!saveas.include_media) {
5096 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5099 save_state ("", false, false, !saveas.include_media);
5101 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5102 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5105 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5106 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5112 if (fs->within_session()) {
5113 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5114 fs->set_path (newpath);
5119 } catch (Glib::FileError& e) {
5121 saveas.failure_message = e.what();
5123 /* recursively remove all the directories */
5125 remove_directory (to_dir);
5133 saveas.failure_message = _("unknown reason");
5135 /* recursively remove all the directories */
5137 remove_directory (to_dir);
5147 static void set_progress (Progress* p, size_t n, size_t t)
5149 p->set_progress (float (n) / float(t));
5153 Session::archive_session (const std::string& dest,
5154 const std::string& name,
5155 ArchiveEncode compress_audio,
5156 bool only_used_sources,
5159 if (dest.empty () || name.empty ()) {
5163 /* save current values */
5164 bool was_dirty = dirty ();
5165 string old_path = _path;
5166 string old_name = _name;
5167 string old_snapshot = _current_snapshot_name;
5168 string old_sd = _session_dir->root_path();
5169 string old_config_search_path[DataType::num_types];
5170 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5171 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5173 /* ensure that session-path is included in search-path */
5175 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5176 if ((*sd).path == old_path) {
5184 /* create temporary dir to save session to */
5185 #ifdef PLATFORM_WINDOWS
5186 char tmp[256] = "C:\\TEMP\\";
5187 GetTempPath (sizeof (tmp), tmp);
5189 char const* tmp = getenv("TMPDIR");
5194 if ((strlen (tmp) + 21) > 1024) {
5199 strcpy (tmptpl, tmp);
5200 strcat (tmptpl, "ardourarchive-XXXXXX");
5201 char* tmpdir = g_mkdtemp (tmptpl);
5207 std::string to_dir = std::string (tmpdir);
5209 /* switch session directory temporarily */
5210 (*_session_dir) = to_dir;
5212 if (!_session_dir->create()) {
5213 (*_session_dir) = old_sd;
5214 remove_directory (to_dir);
5218 /* prepare archive */
5219 string archive = Glib::build_filename (dest, name + ".tar.xz");
5221 PBD::ScopedConnectionList progress_connection;
5222 PBD::FileArchive ar (archive);
5224 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5227 /* collect files to archive */
5228 std::map<string,string> filemap;
5230 vector<string> do_not_copy_extensions;
5231 do_not_copy_extensions.push_back (statefile_suffix);
5232 do_not_copy_extensions.push_back (pending_suffix);
5233 do_not_copy_extensions.push_back (backup_suffix);
5234 do_not_copy_extensions.push_back (temp_suffix);
5235 do_not_copy_extensions.push_back (history_suffix);
5237 vector<string> blacklist_dirs;
5238 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5239 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5240 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5241 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5242 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5243 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5245 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5246 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5248 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5249 if (only_used_sources) {
5250 playlists->sync_all_regions_with_regions ();
5251 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5254 // collect audio sources for this session, calc total size for encoding
5255 // add option to only include *used* sources (see Session::cleanup_sources)
5256 size_t total_size = 0;
5258 Glib::Threads::Mutex::Lock lm (source_lock);
5259 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5260 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5261 if (!afs || afs->readable_length () == 0) {
5265 if (only_used_sources) {
5269 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5274 std::string from = afs->path();
5276 if (compress_audio != NO_ENCODE) {
5277 total_size += afs->readable_length ();
5279 if (afs->within_session()) {
5280 filemap[from] = make_new_media_path (from, name, name);
5282 filemap[from] = make_new_media_path (from, name, name);
5283 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5290 if (compress_audio != NO_ENCODE) {
5292 progress->set_progress (2); // set to "encoding"
5293 progress->set_progress (0);
5296 Glib::Threads::Mutex::Lock lm (source_lock);
5297 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5298 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5299 if (!afs || afs->readable_length () == 0) {
5303 if (only_used_sources) {
5307 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5312 orig_sources[afs] = afs->path();
5313 orig_gain[afs] = afs->gain();
5315 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5316 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5317 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5320 progress->descend ((float)afs->readable_length () / total_size);
5324 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5325 afs->replace_file (new_path);
5326 afs->set_gain (ns->gain(), true);
5329 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5333 progress->ascend ();
5339 progress->set_progress (-1); // set to "archiving"
5340 progress->set_progress (0);
5343 /* index files relevant for this session */
5344 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5345 vector<string> files;
5347 size_t prefix_len = (*sd).path.size();
5348 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5352 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5354 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5355 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5356 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5358 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5359 std::string from = *i;
5362 string filename = Glib::path_get_basename (from);
5363 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5364 if (filename == ".DS_STORE") {
5369 if (from.find (audiofile_dir_string) != string::npos) {
5371 } else if (from.find (midifile_dir_string) != string::npos) {
5372 filemap[from] = make_new_media_path (from, name, name);
5373 } else if (from.find (videofile_dir_string) != string::npos) {
5374 filemap[from] = make_new_media_path (from, name, name);
5376 bool do_copy = true;
5377 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5378 if (from.find (*v) != string::npos) {
5383 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5384 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5391 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5397 /* write session file */
5399 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5401 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5404 save_default_options ();
5406 size_t prefix_len = _path.size();
5407 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5411 /* collect session-state files */
5412 vector<string> files;
5413 do_not_copy_extensions.clear ();
5414 do_not_copy_extensions.push_back (history_suffix);
5416 blacklist_dirs.clear ();
5417 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5419 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5420 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5421 std::string from = *i;
5422 bool do_copy = true;
5423 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5424 if (from.find (*v) != string::npos) {
5429 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5430 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5436 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5440 /* restore original values */
5443 set_snapshot_name (old_snapshot);
5444 (*_session_dir) = old_sd;
5448 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5449 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5451 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5452 i->first->replace_file (i->second);
5454 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5455 i->first->set_gain (i->second, true);
5458 int rv = ar.create (filemap);
5459 remove_directory (to_dir);
5465 Session::undo (uint32_t n)
5467 if (actively_recording()) {
5475 Session::redo (uint32_t n)
5477 if (actively_recording()) {