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 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1751 pl_prop = node.property (X_("midi-playlist"));
1754 DataType type = DataType::AUDIO;
1755 node.get_property("default-type", type);
1757 assert (type != DataType::NIL);
1761 /* has at least 1 playlist, therefore a track ... */
1763 boost::shared_ptr<Track> track;
1765 if (type == DataType::AUDIO) {
1766 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1768 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1771 if (track->init()) {
1775 if (track->set_state (node, version)) {
1779 BOOST_MARK_TRACK (track);
1783 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1784 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1786 if (r->init () == 0 && r->set_state (node, version) == 0) {
1787 BOOST_MARK_ROUTE (r);
1795 boost::shared_ptr<Route>
1796 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1798 boost::shared_ptr<Route> ret;
1800 if (node.name() != "Route") {
1804 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1806 ds_prop = node.property (X_("diskstream"));
1809 DataType type = DataType::AUDIO;
1810 node.get_property("default-type", type);
1812 assert (type != DataType::NIL);
1816 /* see comment in current ::set_state() regarding diskstream
1817 * state and DiskReader/DiskWRiter.
1820 error << _("Could not find diskstream for route") << endmsg;
1821 return boost::shared_ptr<Route> ();
1823 boost::shared_ptr<Track> track;
1825 if (type == DataType::AUDIO) {
1826 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1828 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1831 if (track->init()) {
1835 if (track->set_state (node, version)) {
1839 BOOST_MARK_TRACK (track);
1843 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1844 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1846 if (r->init () == 0 && r->set_state (node, version) == 0) {
1847 BOOST_MARK_ROUTE (r);
1856 Session::load_regions (const XMLNode& node)
1859 XMLNodeConstIterator niter;
1860 boost::shared_ptr<Region> region;
1862 nlist = node.children();
1866 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1867 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1868 error << _("Session: cannot create Region from XML description.");
1869 XMLProperty const * name = (**niter).property("name");
1872 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1883 Session::load_compounds (const XMLNode& node)
1885 XMLNodeList calist = node.children();
1886 XMLNodeConstIterator caiter;
1887 XMLProperty const * caprop;
1889 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1890 XMLNode* ca = *caiter;
1894 if ((caprop = ca->property (X_("original"))) == 0) {
1897 orig_id = caprop->value();
1899 if ((caprop = ca->property (X_("copy"))) == 0) {
1902 copy_id = caprop->value();
1904 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1905 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1907 if (!orig || !copy) {
1908 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1914 RegionFactory::add_compound_association (orig, copy);
1921 Session::load_nested_sources (const XMLNode& node)
1924 XMLNodeConstIterator niter;
1926 nlist = node.children();
1928 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1929 if ((*niter)->name() == "Source") {
1931 /* it may already exist, so don't recreate it unnecessarily
1934 XMLProperty const * prop = (*niter)->property (X_("id"));
1936 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1940 ID source_id (prop->value());
1942 if (!source_by_id (source_id)) {
1945 SourceFactory::create (*this, **niter, true);
1947 catch (failed_constructor& err) {
1948 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1955 boost::shared_ptr<Region>
1956 Session::XMLRegionFactory (const XMLNode& node, bool full)
1958 XMLProperty const * type = node.property("type");
1962 const XMLNodeList& nlist = node.children();
1964 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1965 XMLNode *child = (*niter);
1966 if (child->name() == "NestedSource") {
1967 load_nested_sources (*child);
1971 if (!type || type->value() == "audio") {
1972 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1973 } else if (type->value() == "midi") {
1974 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1977 } catch (failed_constructor& err) {
1978 return boost::shared_ptr<Region> ();
1981 return boost::shared_ptr<Region> ();
1984 boost::shared_ptr<AudioRegion>
1985 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1987 XMLProperty const * prop;
1988 boost::shared_ptr<Source> source;
1989 boost::shared_ptr<AudioSource> as;
1991 SourceList master_sources;
1992 uint32_t nchans = 1;
1995 if (node.name() != X_("Region")) {
1996 return boost::shared_ptr<AudioRegion>();
1999 node.get_property (X_("channels"), nchans);
2001 if ((prop = node.property ("name")) == 0) {
2002 cerr << "no name for this region\n";
2006 if ((prop = node.property (X_("source-0"))) == 0) {
2007 if ((prop = node.property ("source")) == 0) {
2008 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2009 return boost::shared_ptr<AudioRegion>();
2013 PBD::ID s_id (prop->value());
2015 if ((source = source_by_id (s_id)) == 0) {
2016 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2017 return boost::shared_ptr<AudioRegion>();
2020 as = boost::dynamic_pointer_cast<AudioSource>(source);
2022 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2023 return boost::shared_ptr<AudioRegion>();
2026 sources.push_back (as);
2028 /* pickup other channels */
2030 for (uint32_t n=1; n < nchans; ++n) {
2031 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2032 if ((prop = node.property (buf)) != 0) {
2034 PBD::ID id2 (prop->value());
2036 if ((source = source_by_id (id2)) == 0) {
2037 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2038 return boost::shared_ptr<AudioRegion>();
2041 as = boost::dynamic_pointer_cast<AudioSource>(source);
2043 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2044 return boost::shared_ptr<AudioRegion>();
2046 sources.push_back (as);
2050 for (uint32_t n = 0; n < nchans; ++n) {
2051 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2052 if ((prop = node.property (buf)) != 0) {
2054 PBD::ID id2 (prop->value());
2056 if ((source = source_by_id (id2)) == 0) {
2057 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2058 return boost::shared_ptr<AudioRegion>();
2061 as = boost::dynamic_pointer_cast<AudioSource>(source);
2063 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2064 return boost::shared_ptr<AudioRegion>();
2066 master_sources.push_back (as);
2071 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2073 /* a final detail: this is the one and only place that we know how long missing files are */
2075 if (region->whole_file()) {
2076 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2077 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2079 sfp->set_length (region->length());
2084 if (!master_sources.empty()) {
2085 if (master_sources.size() != nchans) {
2086 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2088 region->set_master_sources (master_sources);
2096 catch (failed_constructor& err) {
2097 return boost::shared_ptr<AudioRegion>();
2101 boost::shared_ptr<MidiRegion>
2102 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2104 XMLProperty const * prop;
2105 boost::shared_ptr<Source> source;
2106 boost::shared_ptr<MidiSource> ms;
2109 if (node.name() != X_("Region")) {
2110 return boost::shared_ptr<MidiRegion>();
2113 if ((prop = node.property ("name")) == 0) {
2114 cerr << "no name for this region\n";
2118 if ((prop = node.property (X_("source-0"))) == 0) {
2119 if ((prop = node.property ("source")) == 0) {
2120 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2121 return boost::shared_ptr<MidiRegion>();
2125 PBD::ID s_id (prop->value());
2127 if ((source = source_by_id (s_id)) == 0) {
2128 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2129 return boost::shared_ptr<MidiRegion>();
2132 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2134 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2135 return boost::shared_ptr<MidiRegion>();
2138 sources.push_back (ms);
2141 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2142 /* a final detail: this is the one and only place that we know how long missing files are */
2144 if (region->whole_file()) {
2145 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2146 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2148 sfp->set_length (region->length());
2156 catch (failed_constructor& err) {
2157 return boost::shared_ptr<MidiRegion>();
2162 Session::get_sources_as_xml ()
2165 XMLNode* node = new XMLNode (X_("Sources"));
2166 Glib::Threads::Mutex::Lock lm (source_lock);
2168 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2169 node->add_child_nocopy (i->second->get_state());
2176 Session::reset_write_sources (bool mark_write_complete, bool force)
2178 boost::shared_ptr<RouteList> rl = routes.reader();
2179 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2180 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2182 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2183 tr->reset_write_sources(mark_write_complete, force);
2184 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2190 Session::load_sources (const XMLNode& node)
2193 XMLNodeConstIterator niter;
2194 /* don't need this but it stops some
2195 * versions of gcc complaining about
2196 * discarded return values.
2198 boost::shared_ptr<Source> source;
2200 nlist = node.children();
2203 std::map<std::string, std::string> relocation;
2205 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2206 #ifdef PLATFORM_WINDOWS
2210 XMLNode srcnode (**niter);
2211 bool try_replace_abspath = true;
2215 #ifdef PLATFORM_WINDOWS
2216 // do not show "insert media" popups (files embedded from removable media).
2217 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2219 if ((source = XMLSourceFactory (srcnode)) == 0) {
2220 error << _("Session: cannot create Source from XML description.") << endmsg;
2222 #ifdef PLATFORM_WINDOWS
2223 SetErrorMode(old_mode);
2226 } catch (MissingSource& err) {
2227 #ifdef PLATFORM_WINDOWS
2228 SetErrorMode(old_mode);
2231 /* try previous abs path replacements first */
2232 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2233 std::string dir = Glib::path_get_dirname (err.path);
2234 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2235 if (rl != relocation.end ()) {
2236 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2237 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2238 srcnode.set_property ("origin", newpath);
2239 try_replace_abspath = false;
2246 _missing_file_replacement = "";
2248 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2249 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2250 PROGRAM_NAME) << endmsg;
2254 if (!no_questions_about_missing_files) {
2255 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2260 switch (user_choice) {
2262 /* user added a new search location
2263 * or selected a new absolute path,
2265 if (Glib::path_is_absolute (err.path)) {
2266 if (!_missing_file_replacement.empty ()) {
2267 /* replace origin, in XML */
2268 std::string newpath = Glib::build_filename (
2269 _missing_file_replacement, Glib::path_get_basename (err.path));
2270 srcnode.set_property ("origin", newpath);
2271 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2272 _missing_file_replacement = "";
2279 /* user asked to quit the entire session load */
2283 no_questions_about_missing_files = true;
2287 no_questions_about_missing_files = true;
2294 case DataType::AUDIO:
2295 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2298 case DataType::MIDI:
2299 /* The MIDI file is actually missing so
2300 * just create a new one in the same
2301 * location. Do not announce its
2305 if (!Glib::path_is_absolute (err.path)) {
2306 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2308 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2313 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2314 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2315 /* reset ID to match the missing one */
2316 source->set_id (**niter);
2317 /* Now we can announce it */
2318 SourceFactory::SourceCreated (source);
2329 boost::shared_ptr<Source>
2330 Session::XMLSourceFactory (const XMLNode& node)
2332 if (node.name() != "Source") {
2333 return boost::shared_ptr<Source>();
2337 /* note: do peak building in another thread when loading session state */
2338 return SourceFactory::create (*this, node, true);
2341 catch (failed_constructor& err) {
2342 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2343 return boost::shared_ptr<Source>();
2348 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2350 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2354 bool absolute_path = Glib::path_is_absolute (template_name);
2356 /* directory to put the template in */
2357 std::string template_dir_path;
2359 if (!absolute_path) {
2360 std::string user_template_dir(user_template_directory());
2362 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2363 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2364 user_template_dir, g_strerror (errno)) << endmsg;
2368 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2370 template_dir_path = template_name;
2373 if (!ARDOUR::Profile->get_trx()) {
2374 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2375 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2376 template_dir_path) << endmsg;
2380 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2381 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2382 template_dir_path, g_strerror (errno)) << endmsg;
2388 std::string template_file_path;
2390 if (ARDOUR::Profile->get_trx()) {
2391 template_file_path = template_name;
2393 if (absolute_path) {
2394 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2396 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2400 SessionSaveUnderway (); /* EMIT SIGNAL */
2405 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2406 root = &get_template ();
2409 root->remove_nodes_and_delete (X_("description"));
2411 if (!description.empty()) {
2412 XMLNode* desc = new XMLNode (X_("description"));
2413 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2414 desc->add_child_nocopy (*desc_cont);
2416 root->add_child_nocopy (*desc);
2419 tree.set_root (root);
2421 if (!tree.write (template_file_path)) {
2422 error << _("template not saved") << endmsg;
2426 store_recent_templates (template_file_path);
2432 Session::refresh_disk_space ()
2434 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2436 Glib::Threads::Mutex::Lock lm (space_lock);
2438 /* get freespace on every FS that is part of the session path */
2440 _total_free_4k_blocks = 0;
2441 _total_free_4k_blocks_uncertain = false;
2443 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2444 #if defined(__NetBSD__)
2445 struct statvfs statfsbuf;
2447 statvfs (i->path.c_str(), &statfsbuf);
2449 struct statfs statfsbuf;
2451 statfs (i->path.c_str(), &statfsbuf);
2453 double const scale = statfsbuf.f_bsize / 4096.0;
2455 /* See if this filesystem is read-only */
2456 struct statvfs statvfsbuf;
2457 statvfs (i->path.c_str(), &statvfsbuf);
2459 /* f_bavail can be 0 if it is undefined for whatever
2460 filesystem we are looking at; Samba shares mounted
2461 via GVFS are an example of this.
2463 if (statfsbuf.f_bavail == 0) {
2464 /* block count unknown */
2466 i->blocks_unknown = true;
2467 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2468 /* read-only filesystem */
2470 i->blocks_unknown = false;
2472 /* read/write filesystem with known space */
2473 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2474 i->blocks_unknown = false;
2477 _total_free_4k_blocks += i->blocks;
2478 if (i->blocks_unknown) {
2479 _total_free_4k_blocks_uncertain = true;
2482 #elif defined PLATFORM_WINDOWS
2483 vector<string> scanned_volumes;
2484 vector<string>::iterator j;
2485 vector<space_and_path>::iterator i;
2486 DWORD nSectorsPerCluster, nBytesPerSector,
2487 nFreeClusters, nTotalClusters;
2491 _total_free_4k_blocks = 0;
2493 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2494 strncpy (disk_drive, (*i).path.c_str(), 3);
2498 volume_found = false;
2499 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2501 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2502 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2503 i->blocks = (uint32_t)(nFreeBytes / 4096);
2505 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2506 if (0 == j->compare(disk_drive)) {
2507 volume_found = true;
2512 if (!volume_found) {
2513 scanned_volumes.push_back(disk_drive);
2514 _total_free_4k_blocks += i->blocks;
2519 if (0 == _total_free_4k_blocks) {
2520 strncpy (disk_drive, path().c_str(), 3);
2523 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2525 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2526 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2527 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2534 Session::get_best_session_directory_for_new_audio ()
2536 vector<space_and_path>::iterator i;
2537 string result = _session_dir->root_path();
2539 /* handle common case without system calls */
2541 if (session_dirs.size() == 1) {
2545 /* OK, here's the algorithm we're following here:
2547 We want to select which directory to use for
2548 the next file source to be created. Ideally,
2549 we'd like to use a round-robin process so as to
2550 get maximum performance benefits from splitting
2551 the files across multiple disks.
2553 However, in situations without much diskspace, an
2554 RR approach may end up filling up a filesystem
2555 with new files while others still have space.
2556 Its therefore important to pay some attention to
2557 the freespace in the filesystem holding each
2558 directory as well. However, if we did that by
2559 itself, we'd keep creating new files in the file
2560 system with the most space until it was as full
2561 as all others, thus negating any performance
2562 benefits of this RAID-1 like approach.
2564 So, we use a user-configurable space threshold. If
2565 there are at least 2 filesystems with more than this
2566 much space available, we use RR selection between them.
2567 If not, then we pick the filesystem with the most space.
2569 This gets a good balance between the two
2573 refresh_disk_space ();
2575 int free_enough = 0;
2577 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2578 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2583 if (free_enough >= 2) {
2584 /* use RR selection process, ensuring that the one
2588 i = last_rr_session_dir;
2591 if (++i == session_dirs.end()) {
2592 i = session_dirs.begin();
2595 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2596 SessionDirectory sdir(i->path);
2597 if (sdir.create ()) {
2599 last_rr_session_dir = i;
2604 } while (i != last_rr_session_dir);
2608 /* pick FS with the most freespace (and that
2609 seems to actually work ...)
2612 vector<space_and_path> sorted;
2613 space_and_path_ascending_cmp cmp;
2615 sorted = session_dirs;
2616 sort (sorted.begin(), sorted.end(), cmp);
2618 for (i = sorted.begin(); i != sorted.end(); ++i) {
2619 SessionDirectory sdir(i->path);
2620 if (sdir.create ()) {
2622 last_rr_session_dir = i;
2632 Session::automation_dir () const
2634 return Glib::build_filename (_path, automation_dir_name);
2638 Session::analysis_dir () const
2640 return Glib::build_filename (_path, analysis_dir_name);
2644 Session::plugins_dir () const
2646 return Glib::build_filename (_path, plugins_dir_name);
2650 Session::externals_dir () const
2652 return Glib::build_filename (_path, externals_dir_name);
2656 Session::load_bundles (XMLNode const & node)
2658 XMLNodeList nlist = node.children();
2659 XMLNodeConstIterator niter;
2663 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2664 if ((*niter)->name() == "InputBundle") {
2665 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2666 } else if ((*niter)->name() == "OutputBundle") {
2667 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2669 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2678 Session::load_route_groups (const XMLNode& node, int version)
2680 XMLNodeList nlist = node.children();
2681 XMLNodeConstIterator niter;
2685 if (version >= 3000) {
2687 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2688 if ((*niter)->name() == "RouteGroup") {
2689 RouteGroup* rg = new RouteGroup (*this, "");
2690 add_route_group (rg);
2691 rg->set_state (**niter, version);
2695 } else if (version < 3000) {
2697 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2698 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2699 RouteGroup* rg = new RouteGroup (*this, "");
2700 add_route_group (rg);
2701 rg->set_state (**niter, version);
2710 state_file_filter (const string &str, void* /*arg*/)
2712 return (str.length() > strlen(statefile_suffix) &&
2713 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2717 remove_end(string state)
2719 string statename(state);
2721 string::size_type start,end;
2722 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2723 statename = statename.substr (start+1);
2726 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2727 end = statename.length();
2730 return string(statename.substr (0, end));
2734 Session::possible_states (string path)
2736 vector<string> states;
2737 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2739 transform(states.begin(), states.end(), states.begin(), remove_end);
2741 sort (states.begin(), states.end());
2747 Session::possible_states () const
2749 return possible_states(_path);
2753 Session::new_route_group (const std::string& name)
2755 RouteGroup* rg = NULL;
2757 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2758 if ((*i)->name () == name) {
2765 rg = new RouteGroup (*this, name);
2766 add_route_group (rg);
2772 Session::add_route_group (RouteGroup* g)
2774 _route_groups.push_back (g);
2775 route_group_added (g); /* EMIT SIGNAL */
2777 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2778 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2779 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2785 Session::remove_route_group (RouteGroup& rg)
2787 list<RouteGroup*>::iterator i;
2789 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2790 _route_groups.erase (i);
2793 route_group_removed (); /* EMIT SIGNAL */
2797 /** Set a new order for our route groups, without adding or removing any.
2798 * @param groups Route group list in the new order.
2801 Session::reorder_route_groups (list<RouteGroup*> groups)
2803 _route_groups = groups;
2805 route_groups_reordered (); /* EMIT SIGNAL */
2811 Session::route_group_by_name (string name)
2813 list<RouteGroup *>::iterator i;
2815 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2816 if ((*i)->name() == name) {
2824 Session::all_route_group() const
2826 return *_all_route_group;
2830 Session::add_commands (vector<Command*> const & cmds)
2832 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2838 Session::add_command (Command* const cmd)
2840 assert (_current_trans);
2841 DEBUG_UNDO_HISTORY (
2842 string_compose ("Current Undo Transaction %1, adding command: %2",
2843 _current_trans->name (),
2845 _current_trans->add_command (cmd);
2848 PBD::StatefulDiffCommand*
2849 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2851 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2857 Session::begin_reversible_command (const string& name)
2859 begin_reversible_command (g_quark_from_string (name.c_str ()));
2862 /** Begin a reversible command using a GQuark to identify it.
2863 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2864 * but there must be as many begin...()s as there are commit...()s.
2867 Session::begin_reversible_command (GQuark q)
2869 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2870 to hold all the commands that are committed. This keeps the order of
2871 commands correct in the history.
2874 if (_current_trans == 0) {
2875 DEBUG_UNDO_HISTORY (string_compose (
2876 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2878 /* start a new transaction */
2879 assert (_current_trans_quarks.empty ());
2880 _current_trans = new UndoTransaction();
2881 _current_trans->set_name (g_quark_to_string (q));
2883 DEBUG_UNDO_HISTORY (
2884 string_compose ("Begin Reversible Command, current transaction: %1",
2885 _current_trans->name ()));
2888 _current_trans_quarks.push_front (q);
2892 Session::abort_reversible_command ()
2894 if (_current_trans != 0) {
2895 DEBUG_UNDO_HISTORY (
2896 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2897 _current_trans->clear();
2898 delete _current_trans;
2900 _current_trans_quarks.clear();
2905 Session::commit_reversible_command (Command *cmd)
2907 assert (_current_trans);
2908 assert (!_current_trans_quarks.empty ());
2913 DEBUG_UNDO_HISTORY (
2914 string_compose ("Current Undo Transaction %1, adding command: %2",
2915 _current_trans->name (),
2917 _current_trans->add_command (cmd);
2920 DEBUG_UNDO_HISTORY (
2921 string_compose ("Commit Reversible Command, current transaction: %1",
2922 _current_trans->name ()));
2924 _current_trans_quarks.pop_front ();
2926 if (!_current_trans_quarks.empty ()) {
2927 DEBUG_UNDO_HISTORY (
2928 string_compose ("Commit Reversible Command, transaction is not "
2929 "top-level, current transaction: %1",
2930 _current_trans->name ()));
2931 /* the transaction we're committing is not the top-level one */
2935 if (_current_trans->empty()) {
2936 /* no commands were added to the transaction, so just get rid of it */
2937 DEBUG_UNDO_HISTORY (
2938 string_compose ("Commit Reversible Command, No commands were "
2939 "added to current transaction: %1",
2940 _current_trans->name ()));
2941 delete _current_trans;
2946 gettimeofday (&now, 0);
2947 _current_trans->set_timestamp (now);
2949 _history.add (_current_trans);
2954 accept_all_audio_files (const string& path, void* /*arg*/)
2956 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2960 if (!AudioFileSource::safe_audio_file_extension (path)) {
2968 accept_all_midi_files (const string& path, void* /*arg*/)
2970 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2974 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
2975 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
2976 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2980 accept_all_state_files (const string& path, void* /*arg*/)
2982 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2986 std::string const statefile_ext (statefile_suffix);
2987 if (path.length() >= statefile_ext.length()) {
2988 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2995 Session::find_all_sources (string path, set<string>& result)
3000 if (!tree.read (path)) {
3004 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3009 XMLNodeConstIterator niter;
3011 nlist = node->children();
3015 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3017 XMLProperty const * prop;
3019 if ((prop = (*niter)->property (X_("type"))) == 0) {
3023 DataType type (prop->value());
3025 if ((prop = (*niter)->property (X_("name"))) == 0) {
3029 if (Glib::path_is_absolute (prop->value())) {
3030 /* external file, ignore */
3038 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3039 result.insert (found_path);
3047 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3049 vector<string> state_files;
3051 string this_snapshot_path;
3057 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3058 ripped = ripped.substr (0, ripped.length() - 1);
3061 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3063 if (state_files.empty()) {
3068 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3069 this_snapshot_path += statefile_suffix;
3071 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3073 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3075 if (exclude_this_snapshot && *i == this_snapshot_path) {
3076 cerr << "\texcluded\n";
3081 if (find_all_sources (*i, result) < 0) {
3089 struct RegionCounter {
3090 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3091 AudioSourceList::iterator iter;
3092 boost::shared_ptr<Region> region;
3095 RegionCounter() : count (0) {}
3099 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3101 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3102 return r.get_value_or (1);
3106 Session::cleanup_regions ()
3108 bool removed = false;
3109 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3111 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3113 uint32_t used = playlists->region_use_count (i->second);
3115 if (used == 0 && !i->second->automatic ()) {
3116 boost::weak_ptr<Region> w = i->second;
3119 RegionFactory::map_remove (w);
3126 // re-check to remove parent references of compound regions
3127 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3128 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3132 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3133 if (0 == playlists->region_use_count (i->second)) {
3134 boost::weak_ptr<Region> w = i->second;
3136 RegionFactory::map_remove (w);
3143 /* dump the history list */
3150 Session::can_cleanup_peakfiles () const
3152 if (deletion_in_progress()) {
3155 if (!_writable || (_state_of_the_state & CannotSave)) {
3156 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3159 if (record_status() == Recording) {
3160 error << _("Cannot cleanup peak-files while recording") << endmsg;
3167 Session::cleanup_peakfiles ()
3169 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3174 assert (can_cleanup_peakfiles ());
3175 assert (!peaks_cleanup_in_progres());
3177 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3179 int timeout = 5000; // 5 seconds
3180 while (!SourceFactory::files_with_peaks.empty()) {
3181 Glib::usleep (1000);
3182 if (--timeout < 0) {
3183 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3184 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3189 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3190 boost::shared_ptr<AudioSource> as;
3191 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3192 as->close_peakfile();
3196 PBD::clear_directory (session_directory().peak_path());
3198 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3200 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3201 boost::shared_ptr<AudioSource> as;
3202 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3203 SourceFactory::setup_peakfile(as, true);
3210 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3212 pl->deep_sources (*all_sources);
3216 Session::cleanup_sources (CleanupReport& rep)
3218 // FIXME: needs adaptation to midi
3220 vector<boost::shared_ptr<Source> > dead_sources;
3223 vector<string> candidates;
3224 vector<string> unused;
3225 set<string> sources_used_by_all_snapshots;
3232 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3234 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3236 /* this is mostly for windows which doesn't allow file
3237 * renaming if the file is in use. But we don't special
3238 * case it because we need to know if this causes
3239 * problems, and the easiest way to notice that is to
3240 * keep it in place for all platforms.
3243 request_stop (false);
3245 _butler->wait_until_finished ();
3247 /* consider deleting all unused playlists */
3249 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3254 /* sync the "all regions" property of each playlist with its current state */
3256 playlists->sync_all_regions_with_regions ();
3258 /* find all un-used sources */
3263 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3265 SourceMap::iterator tmp;
3270 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3274 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3275 dead_sources.push_back (i->second);
3276 i->second->drop_references ();
3282 /* build a list of all the possible audio directories for the session */
3284 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3285 SessionDirectory sdir ((*i).path);
3286 asp += sdir.sound_path();
3288 audio_path += asp.to_string();
3291 /* build a list of all the possible midi directories for the session */
3293 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3294 SessionDirectory sdir ((*i).path);
3295 msp += sdir.midi_path();
3297 midi_path += msp.to_string();
3299 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3300 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3302 /* add sources from all other snapshots as "used", but don't use this
3303 snapshot because the state file on disk still references sources we
3304 may have already dropped.
3307 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3309 /* Although the region factory has a list of all regions ever created
3310 * for this session, we're only interested in regions actually in
3311 * playlists right now. So merge all playlist regions lists together.
3313 * This will include the playlists used within compound regions.
3316 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3318 /* add our current source list
3321 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3322 boost::shared_ptr<FileSource> fs;
3323 SourceMap::iterator tmp = i;
3326 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3332 /* this is mostly for windows which doesn't allow file
3333 * renaming if the file is in use. But we do not special
3334 * case it because we need to know if this causes
3335 * problems, and the easiest way to notice that is to
3336 * keep it in place for all platforms.
3341 if (!fs->is_stub()) {
3343 /* Note that we're checking a list of all
3344 * sources across all snapshots with the list
3345 * of sources used by this snapshot.
3348 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3349 /* this source is in use by this snapshot */
3350 sources_used_by_all_snapshots.insert (fs->path());
3351 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3353 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3354 /* this source is NOT in use by this snapshot */
3356 /* remove all related regions from RegionFactory master list */
3358 RegionFactory::remove_regions_using_source (i->second);
3360 /* remove from our current source list
3361 * also. We may not remove it from
3362 * disk, because it may be used by
3363 * other snapshots, but it isn't used inside this
3364 * snapshot anymore, so we don't need a
3375 /* now check each candidate source to see if it exists in the list of
3376 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3379 cerr << "Candidates: " << candidates.size() << endl;
3380 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3382 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3387 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3389 tmppath1 = canonical_path (spath);
3390 tmppath2 = canonical_path ((*i));
3392 cerr << "\t => " << tmppath2 << endl;
3394 if (tmppath1 == tmppath2) {
3401 unused.push_back (spath);
3405 cerr << "Actually unused: " << unused.size() << endl;
3407 if (unused.empty()) {
3413 /* now try to move all unused files into the "dead" directory(ies) */
3415 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3420 /* don't move the file across filesystems, just
3421 * stick it in the `dead_dir_name' directory
3422 * on whichever filesystem it was already on.
3425 if ((*x).find ("/sounds/") != string::npos) {
3427 /* old school, go up 1 level */
3429 newpath = Glib::path_get_dirname (*x); // "sounds"
3430 newpath = Glib::path_get_dirname (newpath); // "session-name"
3434 /* new school, go up 4 levels */
3436 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3437 newpath = Glib::path_get_dirname (newpath); // "session-name"
3438 newpath = Glib::path_get_dirname (newpath); // "interchange"
3439 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3442 newpath = Glib::build_filename (newpath, dead_dir_name);
3444 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3445 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3449 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3451 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3453 /* the new path already exists, try versioning */
3455 char buf[PATH_MAX+1];
3459 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3462 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3463 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3467 if (version == 999) {
3468 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3472 newpath = newpath_v;
3477 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3478 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3479 newpath, g_strerror (errno)) << endmsg;
3483 /* see if there an easy to find peakfile for this file, and remove it. */
3485 string base = Glib::path_get_basename (*x);
3486 base += "%A"; /* this is what we add for the channel suffix of all native files,
3487 * or for the first channel of embedded files. it will miss
3488 * some peakfiles for other channels
3490 string peakpath = construct_peak_filepath (base);
3492 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3493 if (::g_unlink (peakpath.c_str ()) != 0) {
3494 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3495 g_strerror (errno)) << endmsg;
3496 /* try to back out */
3497 ::g_rename (newpath.c_str (), _path.c_str ());
3502 rep.paths.push_back (*x);
3503 rep.space += statbuf.st_size;
3506 /* dump the history list */
3510 /* save state so we don't end up a session file
3511 * referring to non-existent sources.
3518 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3524 Session::cleanup_trash_sources (CleanupReport& rep)
3526 // FIXME: needs adaptation for MIDI
3528 vector<space_and_path>::iterator i;
3534 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3536 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3538 clear_directory (dead_dir, &rep.space, &rep.paths);
3545 Session::set_dirty ()
3547 /* return early if there's nothing to do */
3552 /* never mark session dirty during loading */
3553 if (_state_of_the_state & Loading) {
3557 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3558 DirtyChanged(); /* EMIT SIGNAL */
3562 Session::set_clean ()
3564 bool was_dirty = dirty();
3566 _state_of_the_state = Clean;
3569 DirtyChanged(); /* EMIT SIGNAL */
3574 Session::set_deletion_in_progress ()
3576 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3580 Session::clear_deletion_in_progress ()
3582 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3586 Session::add_controllable (boost::shared_ptr<Controllable> c)
3588 /* this adds a controllable to the list managed by the Session.
3589 this is a subset of those managed by the Controllable class
3590 itself, and represents the only ones whose state will be saved
3591 as part of the session.
3594 Glib::Threads::Mutex::Lock lm (controllables_lock);
3595 controllables.insert (c);
3598 struct null_deleter { void operator()(void const *) const {} };
3601 Session::remove_controllable (Controllable* c)
3603 if (_state_of_the_state & Deletion) {
3607 Glib::Threads::Mutex::Lock lm (controllables_lock);
3609 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3611 if (x != controllables.end()) {
3612 controllables.erase (x);
3616 boost::shared_ptr<Controllable>
3617 Session::controllable_by_id (const PBD::ID& id)
3619 Glib::Threads::Mutex::Lock lm (controllables_lock);
3621 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3622 if ((*i)->id() == id) {
3627 return boost::shared_ptr<Controllable>();
3630 boost::shared_ptr<AutomationControl>
3631 Session::automation_control_by_id (const PBD::ID& id)
3633 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3636 boost::shared_ptr<Controllable>
3637 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3639 boost::shared_ptr<Controllable> c;
3640 boost::shared_ptr<Stripable> s;
3641 boost::shared_ptr<Route> r;
3643 switch (desc.top_level_type()) {
3644 case ControllableDescriptor::NamedRoute:
3646 std::string str = desc.top_level_name();
3648 if (str == "Master" || str == "master") {
3650 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3652 } else if (str == "auditioner") {
3655 s = route_by_name (desc.top_level_name());
3661 case ControllableDescriptor::PresentationOrderRoute:
3662 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3665 case ControllableDescriptor::PresentationOrderTrack:
3666 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3669 case ControllableDescriptor::PresentationOrderBus:
3670 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3673 case ControllableDescriptor::PresentationOrderVCA:
3674 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3677 case ControllableDescriptor::SelectionCount:
3678 s = route_by_selected_count (desc.selection_id());
3686 r = boost::dynamic_pointer_cast<Route> (s);
3688 switch (desc.subtype()) {
3689 case ControllableDescriptor::Gain:
3690 c = s->gain_control ();
3693 case ControllableDescriptor::Trim:
3694 c = s->trim_control ();
3697 case ControllableDescriptor::Solo:
3698 c = s->solo_control();
3701 case ControllableDescriptor::Mute:
3702 c = s->mute_control();
3705 case ControllableDescriptor::Recenable:
3706 c = s->rec_enable_control ();
3709 case ControllableDescriptor::PanDirection:
3710 c = s->pan_azimuth_control();
3713 case ControllableDescriptor::PanWidth:
3714 c = s->pan_width_control();
3717 case ControllableDescriptor::PanElevation:
3718 c = s->pan_elevation_control();
3721 case ControllableDescriptor::Balance:
3722 /* XXX simple pan control */
3725 case ControllableDescriptor::PluginParameter:
3727 uint32_t plugin = desc.target (0);
3728 uint32_t parameter_index = desc.target (1);
3730 /* revert to zero based counting */
3736 if (parameter_index > 0) {
3744 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3747 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3748 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3753 case ControllableDescriptor::SendGain: {
3754 uint32_t send = desc.target (0);
3761 c = r->send_level_controllable (send);
3766 /* relax and return a null pointer */
3774 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3777 Stateful::add_instant_xml (node, _path);
3780 if (write_to_config) {
3781 Config->add_instant_xml (node);
3786 Session::instant_xml (const string& node_name)
3788 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3789 if (get_disable_all_loaded_plugins ()) {
3793 return Stateful::instant_xml (node_name, _path);
3797 Session::save_history (string snapshot_name)
3805 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3806 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3810 if (snapshot_name.empty()) {
3811 snapshot_name = _current_snapshot_name;
3814 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3815 const string backup_filename = history_filename + backup_suffix;
3816 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3817 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3819 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3820 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3821 error << _("could not backup old history file, current history not saved") << endmsg;
3826 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3828 if (!tree.write (xml_path))
3830 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3832 if (g_remove (xml_path.c_str()) != 0) {
3833 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3834 xml_path, g_strerror (errno)) << endmsg;
3836 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3837 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3838 backup_path, g_strerror (errno)) << endmsg;
3848 Session::restore_history (string snapshot_name)
3852 if (snapshot_name.empty()) {
3853 snapshot_name = _current_snapshot_name;
3856 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3857 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3859 info << "Loading history from " << xml_path << endmsg;
3861 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3862 info << string_compose (_("%1: no history file \"%2\" for this session."),
3863 _name, xml_path) << endmsg;
3867 if (!tree.read (xml_path)) {
3868 error << string_compose (_("Could not understand session history file \"%1\""),
3869 xml_path) << endmsg;
3876 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3879 UndoTransaction* ut = new UndoTransaction ();
3885 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3886 !t->get_property ("tv-usec", tv_usec)) {
3890 ut->set_name (name);
3894 tv.tv_usec = tv_usec;
3895 ut->set_timestamp(tv);
3897 for (XMLNodeConstIterator child_it = t->children().begin();
3898 child_it != t->children().end(); child_it++)
3900 XMLNode *n = *child_it;
3903 if (n->name() == "MementoCommand" ||
3904 n->name() == "MementoUndoCommand" ||
3905 n->name() == "MementoRedoCommand") {
3907 if ((c = memento_command_factory(n))) {
3911 } else if (n->name() == "NoteDiffCommand") {
3912 PBD::ID id (n->property("midi-source")->value());
3913 boost::shared_ptr<MidiSource> midi_source =
3914 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3916 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3918 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3921 } else if (n->name() == "SysExDiffCommand") {
3923 PBD::ID id (n->property("midi-source")->value());
3924 boost::shared_ptr<MidiSource> midi_source =
3925 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3927 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3929 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3932 } else if (n->name() == "PatchChangeDiffCommand") {
3934 PBD::ID id (n->property("midi-source")->value());
3935 boost::shared_ptr<MidiSource> midi_source =
3936 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3938 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3940 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3943 } else if (n->name() == "StatefulDiffCommand") {
3944 if ((c = stateful_diff_command_factory (n))) {
3945 ut->add_command (c);
3948 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3959 Session::config_changed (std::string p, bool ours)
3965 if (p == "seamless-loop") {
3967 } else if (p == "rf-speed") {
3969 } else if (p == "auto-loop") {
3971 } else if (p == "session-monitoring") {
3973 } else if (p == "auto-input") {
3975 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3976 /* auto-input only makes a difference if we're rolling */
3977 set_track_monitor_input_status (!config.get_auto_input());
3980 } else if (p == "punch-in") {
3984 if ((location = _locations->auto_punch_location()) != 0) {
3986 if (config.get_punch_in ()) {
3987 replace_event (SessionEvent::PunchIn, location->start());
3989 remove_event (location->start(), SessionEvent::PunchIn);
3993 } else if (p == "punch-out") {
3997 if ((location = _locations->auto_punch_location()) != 0) {
3999 if (config.get_punch_out()) {
4000 replace_event (SessionEvent::PunchOut, location->end());
4002 clear_events (SessionEvent::PunchOut);
4006 } else if (p == "edit-mode") {
4008 Glib::Threads::Mutex::Lock lm (playlists->lock);
4010 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4011 (*i)->set_edit_mode (Config->get_edit_mode ());
4014 } else if (p == "use-video-sync") {
4016 waiting_for_sync_offset = config.get_use_video_sync();
4018 } else if (p == "mmc-control") {
4020 //poke_midi_thread ();
4022 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4024 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4026 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4028 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4030 } else if (p == "midi-control") {
4032 //poke_midi_thread ();
4034 } else if (p == "raid-path") {
4036 setup_raid_path (config.get_raid_path());
4038 } else if (p == "timecode-format") {
4042 } else if (p == "video-pullup") {
4046 } else if (p == "seamless-loop") {
4048 if (play_loop && transport_rolling()) {
4049 // to reset diskstreams etc
4050 request_play_loop (true);
4053 } else if (p == "rf-speed") {
4055 cumulative_rf_motion = 0;
4058 } else if (p == "click-sound") {
4060 setup_click_sounds (1);
4062 } else if (p == "click-emphasis-sound") {
4064 setup_click_sounds (-1);
4066 } else if (p == "clicking") {
4068 if (Config->get_clicking()) {
4069 if (_click_io && click_data) { // don't require emphasis data
4076 } else if (p == "click-record-only") {
4078 _click_rec_only = Config->get_click_record_only();
4080 } else if (p == "click-gain") {
4083 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4086 } else if (p == "send-mtc") {
4088 if (Config->get_send_mtc ()) {
4089 /* mark us ready to send */
4090 next_quarter_frame_to_send = 0;
4093 } else if (p == "send-mmc") {
4095 _mmc->enable_send (Config->get_send_mmc ());
4097 } else if (p == "jack-time-master") {
4099 engine().reset_timebase ();
4101 } else if (p == "native-file-header-format") {
4103 if (!first_file_header_format_reset) {
4104 reset_native_file_format ();
4107 first_file_header_format_reset = false;
4109 } else if (p == "native-file-data-format") {
4111 if (!first_file_data_format_reset) {
4112 reset_native_file_format ();
4115 first_file_data_format_reset = false;
4117 } else if (p == "external-sync") {
4118 if (!config.get_external_sync()) {
4119 drop_sync_source ();
4121 switch_to_sync_source (Config->get_sync_source());
4123 } else if (p == "denormal-model") {
4125 } else if (p == "history-depth") {
4126 set_history_depth (Config->get_history_depth());
4127 } else if (p == "remote-model") {
4128 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4131 } else if (p == "initial-program-change") {
4133 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4136 buf[0] = MIDI::program; // channel zero by default
4137 buf[1] = (Config->get_initial_program_change() & 0x7f);
4139 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4141 } else if (p == "solo-mute-override") {
4142 // catch_up_on_solo_mute_override ();
4143 } else if (p == "listen-position" || p == "pfl-position") {
4144 listen_position_changed ();
4145 } else if (p == "solo-control-is-listen-control") {
4146 solo_control_mode_changed ();
4147 } else if (p == "solo-mute-gain") {
4148 _solo_cut_control->Changed (true, Controllable::NoGroup);
4149 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4150 last_timecode_valid = false;
4151 } else if (p == "playback-buffer-seconds") {
4152 AudioSource::allocate_working_buffers (frame_rate());
4153 } else if (p == "ltc-source-port") {
4154 reconnect_ltc_input ();
4155 } else if (p == "ltc-sink-port") {
4156 reconnect_ltc_output ();
4157 } else if (p == "timecode-generator-offset") {
4158 ltc_tx_parse_offset();
4159 } else if (p == "auto-return-target-list") {
4160 follow_playhead_priority ();
4167 Session::set_history_depth (uint32_t d)
4169 _history.set_depth (d);
4172 /** Connect things to the MMC object */
4174 Session::setup_midi_machine_control ()
4176 _mmc = new MIDI::MachineControl;
4178 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4179 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4181 if (!async_out || !async_out) {
4185 /* XXXX argh, passing raw pointers back into libmidi++ */
4187 MIDI::Port* mmc_in = async_in.get();
4188 MIDI::Port* mmc_out = async_out.get();
4190 _mmc->set_ports (mmc_in, mmc_out);
4192 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4193 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4194 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4195 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4196 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4197 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4198 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4199 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4200 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4201 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4202 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4203 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4204 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4206 /* also handle MIDI SPP because its so common */
4208 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4209 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4210 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4213 boost::shared_ptr<Controllable>
4214 Session::solo_cut_control() const
4216 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4217 * controls in Ardour that currently get presented to the user in the GUI that require
4218 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4220 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4221 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4224 return _solo_cut_control;
4228 Session::save_snapshot_name (const std::string & n)
4230 /* assure Stateful::_instant_xml is loaded
4231 * add_instant_xml() only adds to existing data and defaults
4232 * to use an empty Tree otherwise
4234 instant_xml ("LastUsedSnapshot");
4236 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4237 last_used_snapshot->set_property ("name", n);
4238 add_instant_xml (*last_used_snapshot, false);
4242 Session::set_snapshot_name (const std::string & n)
4244 _current_snapshot_name = n;
4245 save_snapshot_name (n);
4249 Session::rename (const std::string& new_name)
4251 string legal_name = legalize_for_path (new_name);
4257 string const old_sources_root = _session_dir->sources_root();
4259 if (!_writable || (_state_of_the_state & CannotSave)) {
4260 error << _("Cannot rename read-only session.") << endmsg;
4261 return 0; // don't show "messed up" warning
4263 if (record_status() == Recording) {
4264 error << _("Cannot rename session while recording") << endmsg;
4265 return 0; // don't show "messed up" warning
4268 StateProtector stp (this);
4273 * interchange subdirectory
4277 * Backup files are left unchanged and not renamed.
4280 /* Windows requires that we close all files before attempting the
4281 * rename. This works on other platforms, but isn't necessary there.
4282 * Leave it in place for all platforms though, since it may help
4283 * catch issues that could arise if the way Source files work ever
4284 * change (since most developers are not using Windows).
4287 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4288 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4294 /* pass one: not 100% safe check that the new directory names don't
4298 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4302 /* this is a stupid hack because Glib::path_get_dirname() is
4303 * lexical-only, and so passing it /a/b/c/ gives a different
4304 * result than passing it /a/b/c ...
4307 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4308 oldstr = oldstr.substr (0, oldstr.length() - 1);
4311 string base = Glib::path_get_dirname (oldstr);
4313 newstr = Glib::build_filename (base, legal_name);
4315 cerr << "Looking for " << newstr << endl;
4317 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4318 cerr << " exists\n";
4327 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4333 /* this is a stupid hack because Glib::path_get_dirname() is
4334 * lexical-only, and so passing it /a/b/c/ gives a different
4335 * result than passing it /a/b/c ...
4338 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4339 oldstr = oldstr.substr (0, oldstr.length() - 1);
4342 string base = Glib::path_get_dirname (oldstr);
4343 newstr = Glib::build_filename (base, legal_name);
4345 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4347 cerr << "Rename " << oldstr << " => " << newstr << endl;
4348 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4349 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4350 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4354 /* Reset path in "session dirs" */
4359 /* reset primary SessionDirectory object */
4362 (*_session_dir) = newstr;
4367 /* now rename directory below session_dir/interchange */
4369 string old_interchange_dir;
4370 string new_interchange_dir;
4372 /* use newstr here because we renamed the path
4373 * (folder/directory) that used to be oldstr to newstr above
4376 v.push_back (newstr);
4377 v.push_back (interchange_dir_name);
4378 v.push_back (Glib::path_get_basename (oldstr));
4380 old_interchange_dir = Glib::build_filename (v);
4383 v.push_back (newstr);
4384 v.push_back (interchange_dir_name);
4385 v.push_back (legal_name);
4387 new_interchange_dir = Glib::build_filename (v);
4389 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4391 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4392 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4393 old_interchange_dir, new_interchange_dir,
4396 error << string_compose (_("renaming %s as %2 failed (%3)"),
4397 old_interchange_dir, new_interchange_dir,
4406 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4407 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4409 cerr << "Rename " << oldstr << " => " << newstr << endl;
4411 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4412 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4413 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4419 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4421 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4422 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4424 cerr << "Rename " << oldstr << " => " << newstr << endl;
4426 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4427 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4428 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4433 /* remove old name from recent sessions */
4434 remove_recent_sessions (_path);
4437 /* update file source paths */
4439 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4440 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4442 string p = fs->path ();
4443 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4445 SourceFactory::setup_peakfile(i->second, true);
4449 set_snapshot_name (new_name);
4454 /* save state again to get everything just right */
4456 save_state (_current_snapshot_name);
4458 /* add to recent sessions */
4460 store_recent_sessions (new_name, _path);
4466 Session::parse_stateful_loading_version (const std::string& version)
4468 if (version.empty ()) {
4469 /* no version implies very old version of Ardour */
4473 if (version.find ('.') != string::npos) {
4474 /* old school version format */
4475 if (version[0] == '2') {
4481 return string_to<int32_t>(version);
4486 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4488 bool found_sr = false;
4489 bool found_data_format = false;
4490 std::string version;
4491 program_version = "";
4493 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4497 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4501 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4504 xmlFreeParserCtxt(ctxt);
4508 xmlNodePtr node = xmlDocGetRootElement(doc);
4511 xmlFreeParserCtxt(ctxt);
4516 /* sample rate & version*/
4519 for (attr = node->properties; attr; attr = attr->next) {
4520 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4521 version = std::string ((char*)attr->children->content);
4523 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4524 sample_rate = atoi ((char*)attr->children->content);
4529 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4533 node = node->children;
4534 while (node != NULL) {
4535 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4536 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4538 program_version = string ((const char*)val);
4539 size_t sep = program_version.find_first_of("-");
4540 if (sep != string::npos) {
4541 program_version = program_version.substr (0, sep);
4546 if (strcmp((const char*) node->name, "Config")) {
4550 for (node = node->children; node; node = node->next) {
4551 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4552 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4554 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4557 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4559 found_data_format = true;
4560 } catch (PBD::unknown_enumeration& e) {}
4570 xmlFreeParserCtxt(ctxt);
4573 return (found_sr && found_data_format) ? 0 : 1;
4577 Session::get_snapshot_from_instant (const std::string& session_dir)
4579 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4581 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4586 if (!tree.read (instant_xml_path)) {
4590 XMLProperty const * prop;
4591 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4592 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4593 return prop->value();
4599 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4600 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4603 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4607 SourcePathMap source_path_map;
4609 boost::shared_ptr<AudioFileSource> afs;
4614 Glib::Threads::Mutex::Lock lm (source_lock);
4616 cerr << " total sources = " << sources.size();
4618 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4619 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4625 if (fs->within_session()) {
4629 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4630 source_path_map[fs->path()].push_back (fs);
4632 SeveralFileSources v;
4634 source_path_map.insert (make_pair (fs->path(), v));
4640 cerr << " fsources = " << total << endl;
4642 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4644 /* tell caller where we are */
4646 string old_path = i->first;
4648 callback (n, total, old_path);
4650 cerr << old_path << endl;
4654 switch (i->second.front()->type()) {
4655 case DataType::AUDIO:
4656 new_path = new_audio_source_path_for_embedded (old_path);
4659 case DataType::MIDI:
4660 /* XXX not implemented yet */
4664 if (new_path.empty()) {
4668 cerr << "Move " << old_path << " => " << new_path << endl;
4670 if (!copy_file (old_path, new_path)) {
4671 cerr << "failed !\n";
4675 /* make sure we stop looking in the external
4676 dir/folder. Remember, this is an all-or-nothing
4677 operations, it doesn't merge just some files.
4679 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4681 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4682 (*f)->set_path (new_path);
4687 save_state ("", false, false);
4693 bool accept_all_files (string const &, void *)
4699 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4701 /* 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.
4706 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4708 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4710 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4712 v.push_back (new_session_folder); /* full path */
4713 v.push_back (interchange_dir_name);
4714 v.push_back (new_session_path); /* just one directory/folder */
4715 v.push_back (typedir);
4716 v.push_back (Glib::path_get_basename (old_path));
4718 return Glib::build_filename (v);
4722 Session::save_as (SaveAs& saveas)
4724 vector<string> files;
4725 string current_folder = Glib::path_get_dirname (_path);
4726 string new_folder = legalize_for_path (saveas.new_name);
4727 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4728 int64_t total_bytes = 0;
4732 int32_t internal_file_cnt = 0;
4734 vector<string> do_not_copy_extensions;
4735 do_not_copy_extensions.push_back (statefile_suffix);
4736 do_not_copy_extensions.push_back (pending_suffix);
4737 do_not_copy_extensions.push_back (backup_suffix);
4738 do_not_copy_extensions.push_back (temp_suffix);
4739 do_not_copy_extensions.push_back (history_suffix);
4741 /* get total size */
4743 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4745 /* need to clear this because
4746 * find_files_matching_filter() is cumulative
4751 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4753 all += files.size();
4755 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4757 g_stat ((*i).c_str(), &gsb);
4758 total_bytes += gsb.st_size;
4762 /* save old values so we can switch back if we are not switching to the new session */
4764 string old_path = _path;
4765 string old_name = _name;
4766 string old_snapshot = _current_snapshot_name;
4767 string old_sd = _session_dir->root_path();
4768 vector<string> old_search_path[DataType::num_types];
4769 string old_config_search_path[DataType::num_types];
4771 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4772 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4773 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4774 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4776 /* switch session directory */
4778 (*_session_dir) = to_dir;
4780 /* create new tree */
4782 if (!_session_dir->create()) {
4783 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4788 /* copy all relevant files. Find each location in session_dirs,
4789 * and copy files from there to target.
4792 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4794 /* need to clear this because
4795 * find_files_matching_filter() is cumulative
4800 const size_t prefix_len = (*sd).path.size();
4802 /* Work just on the files within this session dir */
4804 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4806 /* add dir separator to protect against collisions with
4807 * track names (e.g. track named "audiofiles" or
4811 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4812 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4813 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4815 /* copy all the files. Handling is different for media files
4816 than others because of the *silly* subtree we have below the interchange
4817 folder. That really was a bad idea, but I'm not fixing it as part of
4818 implementing ::save_as().
4821 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4823 std::string from = *i;
4826 string filename = Glib::path_get_basename (from);
4827 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4828 if (filename == ".DS_STORE") {
4833 if (from.find (audiofile_dir_string) != string::npos) {
4835 /* audio file: only copy if asked */
4837 if (saveas.include_media && saveas.copy_media) {
4839 string to = make_new_media_path (*i, to_dir, new_folder);
4841 info << "media file copying from " << from << " to " << to << endmsg;
4843 if (!copy_file (from, to)) {
4844 throw Glib::FileError (Glib::FileError::IO_ERROR,
4845 string_compose(_("\ncopying \"%1\" failed !"), from));
4849 /* we found media files inside the session folder */
4851 internal_file_cnt++;
4853 } else if (from.find (midifile_dir_string) != string::npos) {
4855 /* midi file: always copy unless
4856 * creating an empty new session
4859 if (saveas.include_media) {
4861 string to = make_new_media_path (*i, to_dir, new_folder);
4863 info << "media file copying from " << from << " to " << to << endmsg;
4865 if (!copy_file (from, to)) {
4866 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4870 /* we found media files inside the session folder */
4872 internal_file_cnt++;
4874 } else if (from.find (analysis_dir_string) != string::npos) {
4876 /* make sure analysis dir exists in
4877 * new session folder, but we're not
4878 * copying analysis files here, see
4882 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4887 /* normal non-media file. Don't copy state, history, etc.
4890 bool do_copy = true;
4892 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4893 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4894 /* end of filename matches extension, do not copy file */
4900 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4901 /* don't copy peakfiles if
4902 * we're not copying media
4908 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4910 info << "attempting to make directory/folder " << to << endmsg;
4912 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4913 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4916 info << "attempting to copy " << from << " to " << to << endmsg;
4918 if (!copy_file (from, to)) {
4919 throw Glib::FileError (Glib::FileError::IO_ERROR,
4920 string_compose(_("\ncopying \"%1\" failed !"), from));
4925 /* measure file size even if we're not going to copy so that our Progress
4926 signals are correct, since we included these do-not-copy files
4927 in the computation of the total size and file count.
4931 g_stat (from.c_str(), &gsb);
4932 copied += gsb.st_size;
4935 double fraction = (double) copied / total_bytes;
4937 bool keep_going = true;
4939 if (saveas.copy_media) {
4941 /* no need or expectation of this if
4942 * media is not being copied, because
4943 * it will be fast(ish).
4946 /* tell someone "X percent, file M of N"; M is one-based */
4948 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4956 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4962 /* copy optional folders, if any */
4964 string old = plugins_dir ();
4965 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4966 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4967 copy_files (old, newdir);
4970 old = externals_dir ();
4971 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4972 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4973 copy_files (old, newdir);
4976 old = automation_dir ();
4977 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4978 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4979 copy_files (old, newdir);
4982 if (saveas.include_media) {
4984 if (saveas.copy_media) {
4985 #ifndef PLATFORM_WINDOWS
4986 /* There are problems with analysis files on
4987 * Windows, because they used a colon in their
4988 * names as late as 4.0. Colons are not legal
4989 * under Windows even if NTFS allows them.
4991 * This is a tricky problem to solve so for
4992 * just don't copy these files. They will be
4993 * regenerated as-needed anyway, subject to the
4994 * existing issue that the filenames will be
4995 * rejected by Windows, which is a separate
4996 * problem (though related).
4999 /* only needed if we are copying media, since the
5000 * analysis data refers to media data
5003 old = analysis_dir ();
5004 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5005 string newdir = Glib::build_filename (to_dir, "analysis");
5006 copy_files (old, newdir);
5008 #endif /* PLATFORM_WINDOWS */
5013 set_snapshot_name (saveas.new_name);
5014 _name = saveas.new_name;
5016 if (saveas.include_media && !saveas.copy_media) {
5018 /* reset search paths of the new session (which we're pretending to be right now) to
5019 include the original session search path, so we can still find all audio.
5022 if (internal_file_cnt) {
5023 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5024 ensure_search_path_includes (*s, DataType::AUDIO);
5025 cerr << "be sure to include " << *s << " for audio" << endl;
5028 /* we do not do this for MIDI because we copy
5029 all MIDI files if saveas.include_media is
5035 bool was_dirty = dirty ();
5037 save_default_options ();
5039 if (saveas.copy_media && saveas.copy_external) {
5040 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5041 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5045 saveas.final_session_folder_name = _path;
5047 store_recent_sessions (_name, _path);
5049 if (!saveas.switch_to) {
5051 /* save the new state */
5053 save_state ("", false, false, !saveas.include_media);
5055 /* switch back to the way things were */
5059 set_snapshot_name (old_snapshot);
5061 (*_session_dir) = old_sd;
5067 if (internal_file_cnt) {
5068 /* reset these to their original values */
5069 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5070 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5075 /* prune session dirs, and update disk space statistics
5080 session_dirs.clear ();
5081 session_dirs.push_back (sp);
5082 refresh_disk_space ();
5084 _writable = exists_and_writable (_path);
5086 /* ensure that all existing tracks reset their current capture source paths
5088 reset_write_sources (true, true);
5090 /* creating new write sources marks the session as
5091 dirty. If the new session is empty, then
5092 save_state() thinks we're saving a template and will
5093 not mark the session as clean. So do that here,
5094 before we save state.
5097 if (!saveas.include_media) {
5098 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5101 save_state ("", false, false, !saveas.include_media);
5103 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5104 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5107 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5108 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5114 if (fs->within_session()) {
5115 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5116 fs->set_path (newpath);
5121 } catch (Glib::FileError& e) {
5123 saveas.failure_message = e.what();
5125 /* recursively remove all the directories */
5127 remove_directory (to_dir);
5135 saveas.failure_message = _("unknown reason");
5137 /* recursively remove all the directories */
5139 remove_directory (to_dir);
5149 static void set_progress (Progress* p, size_t n, size_t t)
5151 p->set_progress (float (n) / float(t));
5155 Session::archive_session (const std::string& dest,
5156 const std::string& name,
5157 ArchiveEncode compress_audio,
5158 bool only_used_sources,
5161 if (dest.empty () || name.empty ()) {
5165 /* save current values */
5166 bool was_dirty = dirty ();
5167 string old_path = _path;
5168 string old_name = _name;
5169 string old_snapshot = _current_snapshot_name;
5170 string old_sd = _session_dir->root_path();
5171 string old_config_search_path[DataType::num_types];
5172 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5173 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5175 /* ensure that session-path is included in search-path */
5177 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5178 if ((*sd).path == old_path) {
5186 /* create temporary dir to save session to */
5187 #ifdef PLATFORM_WINDOWS
5188 char tmp[256] = "C:\\TEMP\\";
5189 GetTempPath (sizeof (tmp), tmp);
5191 char const* tmp = getenv("TMPDIR");
5196 if ((strlen (tmp) + 21) > 1024) {
5201 strcpy (tmptpl, tmp);
5202 strcat (tmptpl, "ardourarchive-XXXXXX");
5203 char* tmpdir = g_mkdtemp (tmptpl);
5209 std::string to_dir = std::string (tmpdir);
5211 /* switch session directory temporarily */
5212 (*_session_dir) = to_dir;
5214 if (!_session_dir->create()) {
5215 (*_session_dir) = old_sd;
5216 remove_directory (to_dir);
5220 /* prepare archive */
5221 string archive = Glib::build_filename (dest, name + ".tar.xz");
5223 PBD::ScopedConnectionList progress_connection;
5224 PBD::FileArchive ar (archive);
5226 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5229 /* collect files to archive */
5230 std::map<string,string> filemap;
5232 vector<string> do_not_copy_extensions;
5233 do_not_copy_extensions.push_back (statefile_suffix);
5234 do_not_copy_extensions.push_back (pending_suffix);
5235 do_not_copy_extensions.push_back (backup_suffix);
5236 do_not_copy_extensions.push_back (temp_suffix);
5237 do_not_copy_extensions.push_back (history_suffix);
5239 vector<string> blacklist_dirs;
5240 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5241 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5242 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5243 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5244 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5245 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5247 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5248 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5250 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5251 if (only_used_sources) {
5252 playlists->sync_all_regions_with_regions ();
5253 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5256 // collect audio sources for this session, calc total size for encoding
5257 // add option to only include *used* sources (see Session::cleanup_sources)
5258 size_t total_size = 0;
5260 Glib::Threads::Mutex::Lock lm (source_lock);
5261 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5262 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5263 if (!afs || afs->readable_length () == 0) {
5267 if (only_used_sources) {
5271 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5276 std::string from = afs->path();
5278 if (compress_audio != NO_ENCODE) {
5279 total_size += afs->readable_length ();
5281 if (afs->within_session()) {
5282 filemap[from] = make_new_media_path (from, name, name);
5284 filemap[from] = make_new_media_path (from, name, name);
5285 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5292 if (compress_audio != NO_ENCODE) {
5294 progress->set_progress (2); // set to "encoding"
5295 progress->set_progress (0);
5298 Glib::Threads::Mutex::Lock lm (source_lock);
5299 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5300 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5301 if (!afs || afs->readable_length () == 0) {
5305 if (only_used_sources) {
5309 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5314 orig_sources[afs] = afs->path();
5315 orig_gain[afs] = afs->gain();
5317 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5318 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5319 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5322 progress->descend ((float)afs->readable_length () / total_size);
5326 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5327 afs->replace_file (new_path);
5328 afs->set_gain (ns->gain(), true);
5331 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5335 progress->ascend ();
5341 progress->set_progress (-1); // set to "archiving"
5342 progress->set_progress (0);
5345 /* index files relevant for this session */
5346 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5347 vector<string> files;
5349 size_t prefix_len = (*sd).path.size();
5350 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5354 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5356 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5357 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5358 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5360 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5361 std::string from = *i;
5364 string filename = Glib::path_get_basename (from);
5365 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5366 if (filename == ".DS_STORE") {
5371 if (from.find (audiofile_dir_string) != string::npos) {
5373 } else if (from.find (midifile_dir_string) != string::npos) {
5374 filemap[from] = make_new_media_path (from, name, name);
5375 } else if (from.find (videofile_dir_string) != string::npos) {
5376 filemap[from] = make_new_media_path (from, name, name);
5378 bool do_copy = true;
5379 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5380 if (from.find (*v) != string::npos) {
5385 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5386 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5393 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5399 /* write session file */
5401 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5403 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5406 save_default_options ();
5408 size_t prefix_len = _path.size();
5409 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5413 /* collect session-state files */
5414 vector<string> files;
5415 do_not_copy_extensions.clear ();
5416 do_not_copy_extensions.push_back (history_suffix);
5418 blacklist_dirs.clear ();
5419 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5421 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5422 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5423 std::string from = *i;
5424 bool do_copy = true;
5425 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5426 if (from.find (*v) != string::npos) {
5431 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5432 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5438 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5442 /* restore original values */
5445 set_snapshot_name (old_snapshot);
5446 (*_session_dir) = old_sd;
5450 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5451 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5453 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5454 i->first->replace_file (i->second);
5456 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5457 i->first->set_gain (i->second, true);
5460 int rv = ar.create (filemap);
5461 remove_directory (to_dir);
5467 Session::undo (uint32_t n)
5469 if (actively_recording()) {
5477 Session::redo (uint32_t n)
5479 if (actively_recording()) {