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_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/types_convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/audioregion.h"
84 #include "ardour/auditioner.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/boost_debug.h"
87 #include "ardour/butler.h"
88 #include "ardour/control_protocol_manager.h"
89 #include "ardour/directory_names.h"
90 #include "ardour/disk_reader.h"
91 #include "ardour/filename_extensions.h"
92 #include "ardour/graph.h"
93 #include "ardour/location.h"
95 #include "ardour/lv2_plugin.h"
97 #include "ardour/midi_model.h"
98 #include "ardour/midi_patch_manager.h"
99 #include "ardour/midi_region.h"
100 #include "ardour/midi_scene_changer.h"
101 #include "ardour/midi_source.h"
102 #include "ardour/midi_track.h"
103 #include "ardour/pannable.h"
104 #include "ardour/playlist_factory.h"
105 #include "ardour/playlist_source.h"
106 #include "ardour/port.h"
107 #include "ardour/processor.h"
108 #include "ardour/progress.h"
109 #include "ardour/profile.h"
110 #include "ardour/proxy_controllable.h"
111 #include "ardour/recent_sessions.h"
112 #include "ardour/region_factory.h"
113 #include "ardour/revision.h"
114 #include "ardour/route_group.h"
115 #include "ardour/send.h"
116 #include "ardour/selection.h"
117 #include "ardour/session.h"
118 #include "ardour/session_directory.h"
119 #include "ardour/session_metadata.h"
120 #include "ardour/session_playlists.h"
121 #include "ardour/session_state_utils.h"
122 #include "ardour/silentfilesource.h"
123 #include "ardour/smf_source.h"
124 #include "ardour/sndfilesource.h"
125 #include "ardour/source_factory.h"
126 #include "ardour/speakers.h"
127 #include "ardour/template_utils.h"
128 #include "ardour/tempo.h"
129 #include "ardour/ticker.h"
130 #include "ardour/transport_master_manager.h"
131 #include "ardour/types_convert.h"
132 #include "ardour/user_bundle.h"
133 #include "ardour/vca.h"
134 #include "ardour/vca_manager.h"
136 #include "control_protocol/control_protocol.h"
138 #include "LuaBridge/LuaBridge.h"
140 #include "pbd/i18n.h"
144 using namespace ARDOUR;
147 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
150 Session::pre_engine_init (string fullpath)
152 if (fullpath.empty()) {
154 throw failed_constructor();
157 /* discover canonical fullpath */
159 _path = canonical_path(fullpath);
162 if (Profile->get_trx() ) {
163 // Waves TracksLive has a usecase of session replacement with a new one.
164 // We should check session state file (<session_name>.ardour) existance
165 // to determine if the session is new or not
167 string full_session_name = Glib::build_filename( fullpath, _name );
168 full_session_name += statefile_suffix;
170 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
172 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
175 /* finish initialization that can't be done in a normal C++ constructor
179 timerclear (&last_mmc_step);
180 g_atomic_int_set (&processing_prohibited, 0);
181 g_atomic_int_set (&_record_status, Disabled);
182 g_atomic_int_set (&_playback_load, 100);
183 g_atomic_int_set (&_capture_load, 100);
185 _all_route_group->set_active (true, this);
187 if (config.get_use_video_sync()) {
188 waiting_for_sync_offset = true;
190 waiting_for_sync_offset = false;
193 last_rr_session_dir = session_dirs.begin();
195 set_history_depth (Config->get_history_depth());
197 /* default: assume simple stereo speaker configuration */
199 _speakers->setup_default_speakers (2);
201 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
202 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
203 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
204 add_controllable (_solo_cut_control);
206 /* These are all static "per-class" signals */
208 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
209 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
210 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
211 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
212 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
214 /* stop IO objects from doing stuff until we're ready for them */
216 Delivery::disable_panners ();
217 IO::disable_connecting ();
221 Session::post_engine_init ()
223 BootMessage (_("Set block size and sample rate"));
225 set_block_size (_engine.samples_per_cycle());
226 set_sample_rate (_engine.sample_rate());
228 BootMessage (_("Using configuration"));
230 _midi_ports = new MidiPortManager;
232 MIDISceneChanger* msc;
234 _scene_changer = msc = new MIDISceneChanger (*this);
235 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
236 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
238 boost::function<samplecnt_t(void)> timer_func (boost::bind (&Session::audible_sample, this, (bool*)(0)));
239 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
241 setup_midi_machine_control ();
243 if (_butler->start_thread()) {
244 error << _("Butler did not start") << endmsg;
248 if (start_midi_thread ()) {
249 error << _("MIDI I/O thread did not start") << endmsg;
253 setup_click_sounds (0);
254 setup_midi_control ();
256 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
257 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
260 /* tempo map requires sample rate knowledge */
263 _tempo_map = new TempoMap (_current_sample_rate);
264 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
265 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
266 } catch (std::exception const & e) {
267 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
270 error << _("Unknown exception during session setup") << endmsg;
275 /* MidiClock requires a tempo map */
278 midi_clock = new MidiClockTicker ();
279 midi_clock->set_session (this);
281 /* crossfades require sample rate knowledge */
283 SndFileSource::setup_standard_crossfades (*this, sample_rate());
284 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
285 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
287 DiskReader::allocate_working_buffers();
288 refresh_disk_space ();
290 /* we're finally ready to call set_state() ... all objects have
291 * been created, the engine is running.
296 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
297 error << _("Could not set session state from XML") << endmsg;
300 } catch (PBD::unknown_enumeration& e) {
301 error << _("Session state: ") << e.what() << endmsg;
305 // set_state() will call setup_raid_path(), but if it's a new session we need
306 // to call setup_raid_path() here.
307 setup_raid_path (_path);
312 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
313 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
315 Config->map_parameters (ff);
316 config.map_parameters (ft);
317 _butler->map_parameters ();
319 /* Reset all panners */
321 Delivery::reset_panners ();
323 /* this will cause the CPM to instantiate any protocols that are in use
324 * (or mandatory), which will pass it this Session, and then call
325 * set_state() on each instantiated protocol to match stored state.
328 ControlProtocolManager::instance().set_session (this);
330 /* This must be done after the ControlProtocolManager set_session above,
331 as it will set states for ports which the ControlProtocolManager creates.
334 // XXX set state of MIDI::Port's
335 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
337 /* And this must be done after the MIDI::Manager::set_port_states as
338 * it will try to make connections whose details are loaded by set_port_states.
343 /* Let control protocols know that we are now all connected, so they
344 * could start talking to surfaces if they want to.
347 ControlProtocolManager::instance().midi_connectivity_established ();
349 if (_is_new && !no_auto_connect()) {
350 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
351 auto_connect_master_bus ();
354 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
356 /* update latencies */
358 initialize_latencies ();
360 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
361 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
362 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
364 } catch (AudioEngine::PortRegistrationFailure& err) {
365 error << err.what() << endmsg;
367 } catch (std::exception const & e) {
368 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
371 error << _("Unknown exception during session setup") << endmsg;
375 BootMessage (_("Reset Remote Controls"));
377 // send_full_time_code (0);
378 _engine.transport_locate (0);
380 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
381 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
383 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
386 /* initial program change will be delivered later; see ::config_changed() */
388 _state_of_the_state = Clean;
390 Port::set_connecting_blocked (false);
392 DirtyChanged (); /* EMIT SIGNAL */
396 } else if (state_was_pending) {
398 remove_pending_capture_state ();
399 state_was_pending = false;
402 /* Now, finally, we can fill the playback buffers */
404 BootMessage (_("Filling playback buffers"));
406 boost::shared_ptr<RouteList> rl = routes.reader();
407 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
408 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
409 if (trk && !trk->is_private_route()) {
410 trk->seek (_transport_sample, true);
418 Session::session_loaded ()
422 _state_of_the_state = Clean;
424 DirtyChanged (); /* EMIT SIGNAL */
428 } else if (state_was_pending) {
430 remove_pending_capture_state ();
431 state_was_pending = false;
434 /* Now, finally, we can fill the playback buffers */
436 BootMessage (_("Filling playback buffers"));
437 force_locate (_transport_sample, false);
441 Session::raid_path () const
443 Searchpath raid_search_path;
445 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
446 raid_search_path += (*i).path;
449 return raid_search_path.to_string ();
453 Session::setup_raid_path (string path)
462 session_dirs.clear ();
464 Searchpath search_path(path);
465 Searchpath sound_search_path;
466 Searchpath midi_search_path;
468 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
470 sp.blocks = 0; // not needed
471 session_dirs.push_back (sp);
473 SessionDirectory sdir(sp.path);
475 sound_search_path += sdir.sound_path ();
476 midi_search_path += sdir.midi_path ();
479 // reset the round-robin soundfile path thingie
480 last_rr_session_dir = session_dirs.begin();
484 Session::path_is_within_session (const std::string& path)
486 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
487 if (PBD::path_is_within (i->path, path)) {
495 Session::ensure_subdirs ()
499 dir = session_directory().peak_path();
501 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
502 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 dir = session_directory().sound_path();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = session_directory().midi_path();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
520 dir = session_directory().dead_path();
522 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
523 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
527 dir = session_directory().export_path();
529 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
534 dir = analysis_dir ();
536 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
537 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
541 dir = plugins_dir ();
543 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
544 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
548 dir = externals_dir ();
550 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
551 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
558 /** @param session_template directory containing session template, or empty.
559 * Caller must not hold process lock.
562 Session::create (const string& session_template, BusProfile* bus_profile)
564 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
565 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
569 if (ensure_subdirs ()) {
573 _writable = exists_and_writable (_path);
575 if (!session_template.empty()) {
576 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
578 FILE* in = g_fopen (in_path.c_str(), "rb");
581 /* no need to call legalize_for_path() since the string
582 * in session_template is already a legal path name
584 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
586 FILE* out = g_fopen (out_path.c_str(), "wb");
590 stringstream new_session;
593 size_t charsRead = fread (buf, sizeof(char), 1024, in);
596 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
601 if (charsRead == 0) {
604 new_session.write (buf, charsRead);
608 string file_contents = new_session.str();
609 size_t writeSize = file_contents.length();
610 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
611 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
619 if (!ARDOUR::Profile->get_trx()) {
620 /* Copy plugin state files from template to new session */
621 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
622 copy_recurse (template_plugins, plugins_dir ());
628 error << string_compose (_("Could not open %1 for writing session template"), out_path)
635 error << string_compose (_("Could not open session template %1 for reading"), in_path)
642 if (Profile->get_trx()) {
644 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
645 * Remember that this is a brand new session. Sessions
646 * loaded from saved state will get this range from the saved state.
649 set_session_range_location (0, 0);
651 /* Initial loop location, from absolute zero, length 10 seconds */
653 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
654 _locations->add (loc, true);
655 set_auto_loop_location (loc);
658 _state_of_the_state = Clean;
660 /* set up Master Out and Monitor Out if necessary */
664 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
665 if (bus_profile->master_out_channels) {
666 int rv = add_master_bus (count);
672 if (Config->get_use_monitor_bus())
673 add_monitor_section ();
681 Session::maybe_write_autosave()
683 if (dirty() && record_status() != Recording) {
684 save_state("", true);
689 Session::remove_pending_capture_state ()
691 std::string pending_state_file_path(_session_dir->root_path());
693 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
695 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
697 if (g_remove (pending_state_file_path.c_str()) != 0) {
698 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
699 pending_state_file_path, g_strerror (errno)) << endmsg;
703 /** Rename a state file.
704 * @param old_name Old snapshot name.
705 * @param new_name New snapshot name.
708 Session::rename_state (string old_name, string new_name)
710 if (old_name == _current_snapshot_name || old_name == _name) {
711 /* refuse to rename the current snapshot or the "main" one */
715 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
716 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
718 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
719 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
721 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
722 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
723 old_name, new_name, g_strerror(errno)) << endmsg;
727 /** Remove a state file.
728 * @param snapshot_name Snapshot name.
731 Session::remove_state (string snapshot_name)
733 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
734 // refuse to remove the current snapshot or the "main" one
738 std::string xml_path(_session_dir->root_path());
740 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
742 if (!create_backup_file (xml_path)) {
743 // don't remove it if a backup can't be made
744 // create_backup_file will log the error.
749 if (g_remove (xml_path.c_str()) != 0) {
750 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
751 xml_path, g_strerror (errno)) << endmsg;
754 StateSaved (snapshot_name); /* EMIT SIGNAL */
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, bool for_archive, bool only_used_assets)
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);
769 Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK);
774 if (!_writable || (_state_of_the_state & CannotSave)) {
778 if (g_atomic_int_get(&_suspend_save)) {
782 _save_queued = false;
784 snapshot_t fork_state = NormalSave;
785 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) {
786 /* snapshot, close midi */
787 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
791 const int64_t save_start_time = g_get_monotonic_time();
794 /* tell sources we're saving first, in case they write out to a new file
795 * which should be saved with the state rather than the old one */
796 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
798 i->second->session_saved();
799 } catch (Evoral::SMF::FileError& e) {
800 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
804 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, for_archive);
806 SessionSaveUnderway (); /* EMIT SIGNAL */
808 bool mark_as_clean = true;
809 if (!snapshot_name.empty() && !switch_to_snapshot) {
810 mark_as_clean = false;
814 mark_as_clean = false;
815 tree.set_root (&get_template());
817 tree.set_root (&state (false, fork_state, only_used_assets));
820 if (snapshot_name.empty()) {
821 snapshot_name = _current_snapshot_name;
822 } else if (switch_to_snapshot) {
823 set_snapshot_name (snapshot_name);
826 assert (!snapshot_name.empty());
830 /* proper save: use statefile_suffix (.ardour in English) */
832 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
834 /* make a backup copy of the old file */
836 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
837 // create_backup_file will log the error
843 /* pending save: use pending_suffix (.pending in English) */
844 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
847 std::string tmp_path(_session_dir->root_path());
848 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
851 cerr << "actually writing state to " << tmp_path << endl;
854 if (!tree.write (tmp_path)) {
855 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
856 if (g_remove (tmp_path.c_str()) != 0) {
857 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
858 tmp_path, g_strerror (errno)) << endmsg;
865 cerr << "renaming state to " << xml_path << endl;
868 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
869 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
870 tmp_path, xml_path, g_strerror(errno)) << endmsg;
871 if (g_remove (tmp_path.c_str()) != 0) {
872 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
873 tmp_path, g_strerror (errno)) << endmsg;
879 //Mixbus auto-backup mechanism
880 if(Profile->get_mixbus()) {
881 if (pending) { //"pending" save means it's a backup, or some other non-user-initiated save; a good time to make a backup
882 // make a serialized safety backup
883 // (will make one periodically but only one per hour is left on disk)
884 // these backup files go into a separated folder
887 struct tm local_time;
889 localtime_r (&n, &local_time);
890 strftime (timebuf, sizeof(timebuf), "%y-%m-%d.%H", &local_time);
891 std::string save_path(session_directory().backup_path());
892 save_path += G_DIR_SEPARATOR;
893 save_path += legalize_for_path(_current_snapshot_name);
895 save_path += timebuf;
896 save_path += statefile_suffix;
897 if ( !tree.write (save_path) )
898 error << string_compose(_("Could not save backup file at path \"%1\" (%2)"),
899 save_path, g_strerror (errno)) << endmsg;
902 StateSaved (snapshot_name); /* EMIT SIGNAL */
905 if (!pending && !for_archive) {
907 save_history (snapshot_name);
910 bool was_dirty = dirty();
912 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
915 DirtyChanged (); /* EMIT SIGNAL */
919 StateSaved (snapshot_name); /* EMIT SIGNAL */
923 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
924 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
930 Session::restore_state (string snapshot_name)
933 if (load_state (snapshot_name) == 0) {
934 set_state (*state_tree->root(), Stateful::loading_state_version);
938 // unknown_enumeration
946 Session::load_state (string snapshot_name)
951 state_was_pending = false;
953 /* check for leftover pending state from a crashed capture attempt */
955 std::string xmlpath(_session_dir->root_path());
956 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
958 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
960 /* there is pending state from a crashed capture attempt */
962 boost::optional<int> r = AskAboutPendingState();
963 if (r.get_value_or (1)) {
964 state_was_pending = true;
968 if (!state_was_pending) {
969 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
972 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
973 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
974 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
975 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
980 state_tree = new XMLTree;
984 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
986 if (!state_tree->read (xmlpath)) {
987 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
993 XMLNode const & root (*state_tree->root());
995 if (root.name() != X_("Session")) {
996 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
1002 std::string version;
1003 root.get_property ("version", version);
1004 Stateful::loading_state_version = parse_stateful_loading_version (version);
1006 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
1007 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
1008 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
1011 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1013 std::string backup_path(_session_dir->root_path());
1014 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1015 backup_path = Glib::build_filename (backup_path, backup_filename);
1017 // only create a backup for a given statefile version once
1019 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1021 VersionMismatch (xmlpath, backup_path);
1023 if (!copy_file (xmlpath, backup_path)) {;
1029 save_snapshot_name (snapshot_name);
1035 Session::load_options (const XMLNode& node)
1037 config.set_variables (node);
1042 Session::save_default_options ()
1044 return config.save_state();
1048 Session::get_state ()
1050 /* this is not directly called, but required by PBD::Stateful */
1052 return state (false, NormalSave);
1056 Session::get_template ()
1058 /* if we don't disable rec-enable, diskstreams
1059 will believe they need to store their capture
1060 sources in their state node.
1063 disable_record (false);
1065 return state (true, NormalSave);
1068 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1069 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1072 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1074 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1077 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1081 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1084 XMLNode* node = new XMLNode("TrackState"); // XXX
1087 PlaylistSet playlists; // SessionPlaylists
1090 // these will work with new_route_from_template()
1091 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1092 child = node->add_child ("Routes");
1093 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1094 if ((*i)->is_auditioner()) {
1097 if ((*i)->is_master() || (*i)->is_monitor()) {
1100 child->add_child_nocopy ((*i)->get_state());
1101 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1103 playlists.insert (track->playlist ());
1107 // on load, Regions in the playlists need to resolve and map Source-IDs
1108 // also playlist needs to be merged or created with new-name..
1109 // ... and Diskstream in tracks adjusted to use the correct playlist
1110 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1111 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1112 child->add_child_nocopy ((*i)->get_state ());
1113 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1114 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1115 const Region::SourceList& sl = (*s)->sources ();
1116 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1117 sources.insert (*sli);
1122 child = node->add_child ("Sources");
1123 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1124 child->add_child_nocopy ((*i)->get_state ());
1125 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1127 #ifdef PLATFORM_WINDOWS
1130 string p = fs->path ();
1131 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1135 std::string sn = Glib::build_filename (path, "share.axml");
1138 tree.set_root (node);
1139 return tree.write (sn.c_str());
1143 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
1145 pl->deep_sources (*all_sources);
1150 struct route_id_compare {
1152 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1154 return r1->id () < r2->id ();
1160 Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets)
1163 XMLNode* node = new XMLNode("Session");
1166 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1168 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1170 child = node->add_child ("ProgramVersion");
1171 child->set_property("created-with", created_with);
1173 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1174 child->set_property("modified-with", modified_with);
1176 /* store configuration settings */
1178 if (!save_template) {
1180 node->set_property ("name", _name);
1181 node->set_property ("sample-rate", _base_sample_rate);
1183 if (session_dirs.size() > 1) {
1187 vector<space_and_path>::iterator i = session_dirs.begin();
1188 vector<space_and_path>::iterator next;
1190 ++i; /* skip the first one */
1194 while (i != session_dirs.end()) {
1198 if (next != session_dirs.end()) {
1199 p += G_SEARCHPATH_SEPARATOR;
1208 child = node->add_child ("Path");
1209 child->add_content (p);
1211 node->set_property ("end-is-free", _session_range_end_is_free);
1214 /* save the ID counter */
1216 node->set_property ("id-counter", ID::counter());
1218 node->set_property ("name-counter", name_id_counter ());
1220 /* save the event ID counter */
1222 node->set_property ("event-counter", Evoral::event_id_counter());
1224 /* save the VCA counter */
1226 node->set_property ("vca-counter", VCA::get_next_vca_number());
1228 /* various options */
1230 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1231 if (!midi_port_nodes.empty()) {
1232 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1233 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1234 midi_port_stuff->add_child_nocopy (**n);
1236 node->add_child_nocopy (*midi_port_stuff);
1239 XMLNode& cfgxml (config.get_variables ());
1240 if (save_template) {
1241 /* exclude search-paths from template */
1242 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1243 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1244 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1246 node->add_child_nocopy (cfgxml);
1248 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1250 child = node->add_child ("Sources");
1252 if (!save_template) {
1253 Glib::Threads::Mutex::Lock sl (source_lock);
1255 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1257 if (only_used_assets) {
1258 playlists->sync_all_regions_with_regions ();
1259 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1262 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1264 /* Don't save information about non-file Sources, or
1265 * about non-destructive file sources that are empty
1266 * and unused by any regions.
1268 boost::shared_ptr<FileSource> fs;
1270 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1274 if (!fs->destructive()) {
1275 if (fs->empty() && !fs->used()) {
1280 if (only_used_assets) {
1281 /* skip only unused audio files */
1282 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1283 if (afs && !afs->used()) {
1286 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1291 if (snapshot_type != NormalSave && fs->within_session ()) {
1292 /* copy MIDI sources to new file
1294 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1295 * because the GUI (midi_region) has a direct pointer to the midi-model
1296 * of the source, as does UndoTransaction.
1298 * On the upside, .mid files are not kept open. The file is only open
1299 * when reading the model initially and when flushing the model to disk:
1300 * source->session_saved () or export.
1302 * We can change the _path of the existing source under the hood, keeping
1303 * all IDs, references and pointers intact.
1305 boost::shared_ptr<SMFSource> ms;
1306 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1307 const std::string ancestor_name = ms->ancestor_name();
1308 const std::string base = PBD::basename_nosuffix(ancestor_name);
1309 const string path = new_midi_source_path (base, false);
1311 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1312 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1313 Source::Lock lm (ms->mutex());
1315 // TODO special-case empty, removable() files: just create a new removable.
1316 // (load + write flushes the model and creates the file)
1318 ms->load_model (lm);
1320 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1321 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1323 if (snapshot_type == SnapshotKeep) {
1324 /* keep working on current session.
1326 * Save snapshot-state with the original filename.
1327 * Switch to use new path for future saves of the main session.
1329 child->add_child_nocopy (ms->get_state());
1333 * ~SMFSource unlinks removable() files.
1335 std::string npath (ms->path ());
1336 ms->replace_file (newsrc->path ());
1337 newsrc->replace_file (npath);
1339 if (snapshot_type == SwitchToSnapshot) {
1340 /* save and switch to snapshot.
1342 * Leave the old file in place (as is).
1343 * Snapshot uses new source directly
1345 child->add_child_nocopy (ms->get_state());
1352 child->add_child_nocopy (siter->second->get_state());
1356 child = node->add_child ("Regions");
1358 if (!save_template) {
1359 Glib::Threads::Mutex::Lock rl (region_lock);
1361 if (!only_used_assets) {
1362 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1363 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1364 boost::shared_ptr<Region> r = i->second;
1365 /* only store regions not attached to playlists */
1366 if (r->playlist() == 0) {
1367 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1368 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1370 child->add_child_nocopy (r->get_state ());
1376 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1378 if (!cassocs.empty()) {
1379 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1381 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1382 if (i->first->playlist () == 0 && only_used_assets) {
1385 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1386 can->set_property (X_("copy"), i->first->id());
1387 can->set_property (X_("original"), i->second->id());
1388 ca->add_child_nocopy (*can);
1389 /* see above, child is still "Regions" here */
1390 if (i->second->playlist() == 0 && only_used_assets) {
1391 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1392 child->add_child_nocopy (ar->get_basic_state ());
1394 child->add_child_nocopy (ar->get_state ());
1401 if (!save_template) {
1403 node->add_child_nocopy (_selection->get_state());
1406 node->add_child_nocopy (_locations->get_state());
1409 Locations loc (*this);
1410 const bool was_dirty = dirty();
1411 // for a template, just create a new Locations, populate it
1412 // with the default start and end, and get the state for that.
1413 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1414 range->set (max_samplepos, 0);
1416 XMLNode& locations_state = loc.get_state();
1418 if (ARDOUR::Profile->get_trx() && _locations) {
1419 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1420 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1421 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1422 locations_state.add_child_nocopy ((*i)->get_state ());
1426 node->add_child_nocopy (locations_state);
1428 /* adding a location above will have marked the session
1429 * dirty. This is an artifact, so fix it if the session wasn't
1434 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1438 child = node->add_child ("Bundles");
1440 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1441 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1442 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1444 child->add_child_nocopy (b->get_state());
1449 node->add_child_nocopy (_vca_manager->get_state());
1451 child = node->add_child ("Routes");
1453 boost::shared_ptr<RouteList> r = routes.reader ();
1455 route_id_compare cmp;
1456 RouteList xml_node_order (*r);
1457 xml_node_order.sort (cmp);
1459 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1460 if (!(*i)->is_auditioner()) {
1461 if (save_template) {
1462 child->add_child_nocopy ((*i)->get_template());
1464 child->add_child_nocopy ((*i)->get_state());
1470 playlists->add_state (node, save_template, !only_used_assets);
1472 child = node->add_child ("RouteGroups");
1473 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1474 child->add_child_nocopy ((*i)->get_state());
1478 XMLNode* gain_child = node->add_child ("Click");
1479 gain_child->add_child_nocopy (_click_io->get_state ());
1480 gain_child->add_child_nocopy (_click_gain->get_state ());
1484 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1485 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1488 node->add_child_nocopy (_speakers->get_state());
1489 node->add_child_nocopy (_tempo_map->get_state());
1490 node->add_child_nocopy (get_control_protocol_state());
1493 node->add_child_copy (*_extra_xml);
1497 Glib::Threads::Mutex::Lock lm (lua_lock);
1500 luabridge::LuaRef savedstate ((*_lua_save)());
1501 saved = savedstate.cast<std::string>();
1503 lua.collect_garbage ();
1506 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1507 std::string b64s (b64);
1510 XMLNode* script_node = new XMLNode (X_("Script"));
1511 script_node->set_property (X_("lua"), LUA_VERSION);
1512 script_node->add_content (b64s);
1513 node->add_child_nocopy (*script_node);
1520 Session::get_control_protocol_state ()
1522 return ControlProtocolManager::instance().get_state ();
1526 Session::set_state (const XMLNode& node, int version)
1533 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1535 if (node.name() != X_("Session")) {
1536 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1540 node.get_property ("name", _name);
1542 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1544 _nominal_sample_rate = _base_sample_rate;
1546 assert (AudioEngine::instance()->running ());
1547 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1548 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1549 if (r.get_value_or (0)) {
1555 created_with = "unknown";
1556 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1557 child->get_property (X_("created-with"), created_with);
1560 setup_raid_path(_session_dir->root_path());
1562 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1565 if (node.get_property (X_("id-counter"), counter)) {
1566 ID::init_counter (counter);
1568 /* old sessions used a timebased counter, so fake
1569 * the startup ID counter based on a standard
1574 ID::init_counter (now);
1577 if (node.get_property (X_("name-counter"), counter)) {
1578 init_name_id_counter (counter);
1581 if (node.get_property (X_("event-counter"), counter)) {
1582 Evoral::init_event_id_counter (counter);
1585 if (node.get_property (X_("vca-counter"), counter)) {
1586 VCA::set_next_vca_number (counter);
1588 VCA::set_next_vca_number (1);
1591 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1592 _midi_ports->set_midi_port_states (child->children());
1595 IO::disable_connecting ();
1597 Stateful::save_extra_xml (node);
1599 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1600 load_options (*child);
1601 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1602 load_options (*child);
1604 error << _("Session: XML state has no options section") << endmsg;
1607 if (version >= 3000) {
1608 if ((child = find_named_node (node, "Metadata")) == 0) {
1609 warning << _("Session: XML state has no metadata section") << endmsg;
1610 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1615 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1616 _speakers->set_state (*child, version);
1619 if ((child = find_named_node (node, "Sources")) == 0) {
1620 error << _("Session: XML state has no sources section") << endmsg;
1622 } else if (load_sources (*child)) {
1626 if ((child = find_named_node (node, "TempoMap")) == 0) {
1627 error << _("Session: XML state has no Tempo Map section") << endmsg;
1629 } else if (_tempo_map->set_state (*child, version)) {
1633 if ((child = find_named_node (node, "Locations")) == 0) {
1634 error << _("Session: XML state has no locations section") << endmsg;
1636 } else if (_locations->set_state (*child, version)) {
1640 locations_changed ();
1642 if (_session_range_location) {
1643 AudioFileSource::set_header_position_offset (_session_range_location->start());
1646 if ((child = find_named_node (node, "Regions")) == 0) {
1647 error << _("Session: XML state has no Regions section") << endmsg;
1649 } else if (load_regions (*child)) {
1653 if ((child = find_named_node (node, "Playlists")) == 0) {
1654 error << _("Session: XML state has no playlists section") << endmsg;
1656 } else if (playlists->load (*this, *child)) {
1660 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1662 } else if (playlists->load_unused (*this, *child)) {
1666 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1667 if (load_compounds (*child)) {
1672 if (version >= 3000) {
1673 if ((child = find_named_node (node, "Bundles")) == 0) {
1674 warning << _("Session: XML state has no bundles section") << endmsg;
1677 /* We can't load Bundles yet as they need to be able
1678 * to convert from port names to Port objects, which can't happen until
1680 _bundle_xml_node = new XMLNode (*child);
1684 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1685 _vca_manager->set_state (*child, version);
1688 if ((child = find_named_node (node, "Routes")) == 0) {
1689 error << _("Session: XML state has no routes section") << endmsg;
1691 } else if (load_routes (*child, version)) {
1695 /* Now that we have Routes and masters loaded, connect them if appropriate */
1697 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1699 if (version >= 3000) {
1701 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1702 error << _("Session: XML state has no route groups section") << endmsg;
1704 } else if (load_route_groups (*child, version)) {
1708 } else if (version < 3000) {
1710 if ((child = find_named_node (node, "EditGroups")) == 0) {
1711 error << _("Session: XML state has no edit groups section") << endmsg;
1713 } else if (load_route_groups (*child, version)) {
1717 if ((child = find_named_node (node, "MixGroups")) == 0) {
1718 error << _("Session: XML state has no mix groups section") << endmsg;
1720 } else if (load_route_groups (*child, version)) {
1725 if ((child = find_named_node (node, "Click")) == 0) {
1726 warning << _("Session: XML state has no click section") << endmsg;
1727 } else if (_click_io) {
1728 setup_click_state (&node);
1731 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1732 ControlProtocolManager::instance().set_state (*child, 1 /* here: session-specific state */);
1735 if ((child = find_named_node (node, "Script"))) {
1736 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1737 if (!(*n)->is_content ()) { continue; }
1739 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1741 Glib::Threads::Mutex::Lock lm (lua_lock);
1742 (*_lua_load)(std::string ((const char*)buf, size));
1743 } catch (luabridge::LuaException const& e) {
1744 cerr << "LuaException:" << e.what () << endl;
1750 if ((child = find_named_node (node, X_("Selection")))) {
1751 _selection->set_state (*child, version);
1754 update_route_record_state ();
1756 /* here beginneth the second phase ... */
1757 set_snapshot_name (_current_snapshot_name);
1759 StateReady (); /* EMIT SIGNAL */
1772 Session::load_routes (const XMLNode& node, int version)
1775 XMLNodeConstIterator niter;
1776 RouteList new_routes;
1778 nlist = node.children();
1782 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1784 boost::shared_ptr<Route> route;
1786 if (version < 3000) {
1787 route = XMLRouteFactory_2X (**niter, version);
1788 } else if (version < 5000) {
1789 route = XMLRouteFactory_3X (**niter, version);
1791 route = XMLRouteFactory (**niter, version);
1795 error << _("Session: cannot create Route from XML description.") << endmsg;
1799 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1801 new_routes.push_back (route);
1804 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1806 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1808 BootMessage (_("Finished adding tracks/busses"));
1813 boost::shared_ptr<Route>
1814 Session::XMLRouteFactory (const XMLNode& node, int version)
1816 boost::shared_ptr<Route> ret;
1818 if (node.name() != "Route") {
1822 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1825 pl_prop = node.property (X_("midi-playlist"));
1828 DataType type = DataType::AUDIO;
1829 node.get_property("default-type", type);
1831 assert (type != DataType::NIL);
1835 /* has at least 1 playlist, therefore a track ... */
1837 boost::shared_ptr<Track> track;
1839 if (type == DataType::AUDIO) {
1840 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1842 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1845 if (track->init()) {
1849 if (track->set_state (node, version)) {
1853 BOOST_MARK_TRACK (track);
1857 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1858 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1861 if (r->init () == 0 && r->set_state (node, version) == 0) {
1862 BOOST_MARK_ROUTE (r);
1870 boost::shared_ptr<Route>
1871 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1873 boost::shared_ptr<Route> ret;
1875 if (node.name() != "Route") {
1879 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1881 DataType type = DataType::AUDIO;
1882 node.get_property("default-type", type);
1884 assert (type != DataType::NIL);
1888 boost::shared_ptr<Track> track;
1890 if (type == DataType::AUDIO) {
1891 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1893 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1896 if (track->init()) {
1900 if (track->set_state (node, version)) {
1904 BOOST_MARK_TRACK (track);
1908 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1909 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1911 if (r->init () == 0 && r->set_state (node, version) == 0) {
1912 BOOST_MARK_ROUTE (r);
1920 boost::shared_ptr<Route>
1921 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1923 boost::shared_ptr<Route> ret;
1925 if (node.name() != "Route") {
1929 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1931 ds_prop = node.property (X_("diskstream"));
1934 DataType type = DataType::AUDIO;
1935 node.get_property("default-type", type);
1937 assert (type != DataType::NIL);
1941 /* see comment in current ::set_state() regarding diskstream
1942 * state and DiskReader/DiskWRiter.
1945 error << _("Could not find diskstream for route") << endmsg;
1946 return boost::shared_ptr<Route> ();
1948 boost::shared_ptr<Track> track;
1950 if (type == DataType::AUDIO) {
1951 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1953 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1956 if (track->init()) {
1960 if (track->set_state (node, version)) {
1964 BOOST_MARK_TRACK (track);
1968 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1969 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1971 if (r->init () == 0 && r->set_state (node, version) == 0) {
1972 BOOST_MARK_ROUTE (r);
1981 Session::load_regions (const XMLNode& node)
1984 XMLNodeConstIterator niter;
1985 boost::shared_ptr<Region> region;
1987 nlist = node.children();
1991 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1992 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1993 error << _("Session: cannot create Region from XML description.");
1994 XMLProperty const * name = (**niter).property("name");
1997 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
2008 Session::load_compounds (const XMLNode& node)
2010 XMLNodeList calist = node.children();
2011 XMLNodeConstIterator caiter;
2012 XMLProperty const * caprop;
2014 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
2015 XMLNode* ca = *caiter;
2019 if ((caprop = ca->property (X_("original"))) == 0) {
2022 orig_id = caprop->value();
2024 if ((caprop = ca->property (X_("copy"))) == 0) {
2027 copy_id = caprop->value();
2029 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2030 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2032 if (!orig || !copy) {
2033 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2039 RegionFactory::add_compound_association (orig, copy);
2046 Session::load_nested_sources (const XMLNode& node)
2049 XMLNodeConstIterator niter;
2051 nlist = node.children();
2053 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2054 if ((*niter)->name() == "Source") {
2056 /* it may already exist, so don't recreate it unnecessarily
2059 XMLProperty const * prop = (*niter)->property (X_("id"));
2061 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2065 ID source_id (prop->value());
2067 if (!source_by_id (source_id)) {
2070 SourceFactory::create (*this, **niter, true);
2072 catch (failed_constructor& err) {
2073 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2080 boost::shared_ptr<Region>
2081 Session::XMLRegionFactory (const XMLNode& node, bool full)
2083 XMLProperty const * type = node.property("type");
2087 const XMLNodeList& nlist = node.children();
2089 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2090 XMLNode *child = (*niter);
2091 if (child->name() == "NestedSource") {
2092 load_nested_sources (*child);
2096 if (!type || type->value() == "audio") {
2097 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2098 } else if (type->value() == "midi") {
2099 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2102 } catch (failed_constructor& err) {
2103 return boost::shared_ptr<Region> ();
2106 return boost::shared_ptr<Region> ();
2109 boost::shared_ptr<AudioRegion>
2110 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2112 XMLProperty const * prop;
2113 boost::shared_ptr<Source> source;
2114 boost::shared_ptr<AudioSource> as;
2116 SourceList master_sources;
2117 uint32_t nchans = 1;
2120 if (node.name() != X_("Region")) {
2121 return boost::shared_ptr<AudioRegion>();
2124 node.get_property (X_("channels"), nchans);
2126 if ((prop = node.property ("name")) == 0) {
2127 cerr << "no name for this region\n";
2131 if ((prop = node.property (X_("source-0"))) == 0) {
2132 if ((prop = node.property ("source")) == 0) {
2133 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2134 return boost::shared_ptr<AudioRegion>();
2138 PBD::ID s_id (prop->value());
2140 if ((source = source_by_id (s_id)) == 0) {
2141 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2142 return boost::shared_ptr<AudioRegion>();
2145 as = boost::dynamic_pointer_cast<AudioSource>(source);
2147 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2148 return boost::shared_ptr<AudioRegion>();
2151 sources.push_back (as);
2153 /* pickup other channels */
2155 for (uint32_t n=1; n < nchans; ++n) {
2156 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2157 if ((prop = node.property (buf)) != 0) {
2159 PBD::ID id2 (prop->value());
2161 if ((source = source_by_id (id2)) == 0) {
2162 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2163 return boost::shared_ptr<AudioRegion>();
2166 as = boost::dynamic_pointer_cast<AudioSource>(source);
2168 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2169 return boost::shared_ptr<AudioRegion>();
2171 sources.push_back (as);
2175 for (uint32_t n = 0; n < nchans; ++n) {
2176 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2177 if ((prop = node.property (buf)) != 0) {
2179 PBD::ID id2 (prop->value());
2181 if ((source = source_by_id (id2)) == 0) {
2182 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2183 return boost::shared_ptr<AudioRegion>();
2186 as = boost::dynamic_pointer_cast<AudioSource>(source);
2188 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2189 return boost::shared_ptr<AudioRegion>();
2191 master_sources.push_back (as);
2196 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2198 /* a final detail: this is the one and only place that we know how long missing files are */
2200 if (region->whole_file()) {
2201 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2202 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2204 sfp->set_length (region->length());
2209 if (!master_sources.empty()) {
2210 if (master_sources.size() != nchans) {
2211 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2213 region->set_master_sources (master_sources);
2221 catch (failed_constructor& err) {
2222 return boost::shared_ptr<AudioRegion>();
2226 boost::shared_ptr<MidiRegion>
2227 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2229 XMLProperty const * prop;
2230 boost::shared_ptr<Source> source;
2231 boost::shared_ptr<MidiSource> ms;
2234 if (node.name() != X_("Region")) {
2235 return boost::shared_ptr<MidiRegion>();
2238 if ((prop = node.property ("name")) == 0) {
2239 cerr << "no name for this region\n";
2243 if ((prop = node.property (X_("source-0"))) == 0) {
2244 if ((prop = node.property ("source")) == 0) {
2245 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2246 return boost::shared_ptr<MidiRegion>();
2250 PBD::ID s_id (prop->value());
2252 if ((source = source_by_id (s_id)) == 0) {
2253 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2254 return boost::shared_ptr<MidiRegion>();
2257 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2259 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2260 return boost::shared_ptr<MidiRegion>();
2263 sources.push_back (ms);
2266 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2267 /* a final detail: this is the one and only place that we know how long missing files are */
2269 if (region->whole_file()) {
2270 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2271 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2273 sfp->set_length (region->length());
2281 catch (failed_constructor& err) {
2282 return boost::shared_ptr<MidiRegion>();
2287 Session::get_sources_as_xml ()
2290 XMLNode* node = new XMLNode (X_("Sources"));
2291 Glib::Threads::Mutex::Lock lm (source_lock);
2293 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2294 node->add_child_nocopy (i->second->get_state());
2301 Session::reset_write_sources (bool mark_write_complete, bool force)
2303 boost::shared_ptr<RouteList> rl = routes.reader();
2304 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2305 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2307 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2308 tr->reset_write_sources(mark_write_complete, force);
2309 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2315 Session::load_sources (const XMLNode& node)
2318 XMLNodeConstIterator niter;
2319 /* don't need this but it stops some
2320 * versions of gcc complaining about
2321 * discarded return values.
2323 boost::shared_ptr<Source> source;
2325 nlist = node.children();
2328 std::map<std::string, std::string> relocation;
2330 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2331 #ifdef PLATFORM_WINDOWS
2335 XMLNode srcnode (**niter);
2336 bool try_replace_abspath = true;
2340 #ifdef PLATFORM_WINDOWS
2341 // do not show "insert media" popups (files embedded from removable media).
2342 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2344 if ((source = XMLSourceFactory (srcnode)) == 0) {
2345 error << _("Session: cannot create Source from XML description.") << endmsg;
2347 #ifdef PLATFORM_WINDOWS
2348 SetErrorMode(old_mode);
2351 } catch (MissingSource& err) {
2352 #ifdef PLATFORM_WINDOWS
2353 SetErrorMode(old_mode);
2356 /* try previous abs path replacements first */
2357 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2358 std::string dir = Glib::path_get_dirname (err.path);
2359 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2360 if (rl != relocation.end ()) {
2361 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2362 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2363 srcnode.set_property ("origin", newpath);
2364 try_replace_abspath = false;
2371 _missing_file_replacement = "";
2373 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2374 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2375 PROGRAM_NAME) << endmsg;
2379 if (!no_questions_about_missing_files) {
2380 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2385 switch (user_choice) {
2387 /* user added a new search location
2388 * or selected a new absolute path,
2390 if (Glib::path_is_absolute (err.path)) {
2391 if (!_missing_file_replacement.empty ()) {
2392 /* replace origin, in XML */
2393 std::string newpath = Glib::build_filename (
2394 _missing_file_replacement, Glib::path_get_basename (err.path));
2395 srcnode.set_property ("origin", newpath);
2396 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2397 _missing_file_replacement = "";
2404 /* user asked to quit the entire session load */
2408 no_questions_about_missing_files = true;
2412 no_questions_about_missing_files = true;
2419 case DataType::AUDIO:
2420 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2423 case DataType::MIDI:
2424 /* The MIDI file is actually missing so
2425 * just create a new one in the same
2426 * location. Do not announce its
2430 if (!Glib::path_is_absolute (err.path)) {
2431 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2433 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2438 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2439 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2440 /* reset ID to match the missing one */
2441 source->set_id (**niter);
2442 /* Now we can announce it */
2443 SourceFactory::SourceCreated (source);
2454 boost::shared_ptr<Source>
2455 Session::XMLSourceFactory (const XMLNode& node)
2457 if (node.name() != "Source") {
2458 return boost::shared_ptr<Source>();
2462 /* note: do peak building in another thread when loading session state */
2463 return SourceFactory::create (*this, node, true);
2466 catch (failed_constructor& err) {
2467 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2468 return boost::shared_ptr<Source>();
2473 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2475 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2479 bool absolute_path = Glib::path_is_absolute (template_name);
2481 /* directory to put the template in */
2482 std::string template_dir_path;
2484 if (!absolute_path) {
2485 std::string user_template_dir(user_template_directory());
2487 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2488 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2489 user_template_dir, g_strerror (errno)) << endmsg;
2493 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2495 template_dir_path = template_name;
2498 if (!ARDOUR::Profile->get_trx()) {
2499 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2500 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2501 template_dir_path) << endmsg;
2505 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2506 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2507 template_dir_path, g_strerror (errno)) << endmsg;
2513 std::string template_file_path;
2515 if (ARDOUR::Profile->get_trx()) {
2516 template_file_path = template_name;
2518 if (absolute_path) {
2519 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2521 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2525 SessionSaveUnderway (); /* EMIT SIGNAL */
2530 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2531 root = &get_template ();
2534 root->remove_nodes_and_delete (X_("description"));
2536 if (!description.empty()) {
2537 XMLNode* desc = new XMLNode (X_("description"));
2538 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2539 desc->add_child_nocopy (*desc_cont);
2541 root->add_child_nocopy (*desc);
2544 tree.set_root (root);
2546 if (!tree.write (template_file_path)) {
2547 error << _("template not saved") << endmsg;
2551 store_recent_templates (template_file_path);
2557 Session::refresh_disk_space ()
2559 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2561 Glib::Threads::Mutex::Lock lm (space_lock);
2563 /* get freespace on every FS that is part of the session path */
2565 _total_free_4k_blocks = 0;
2566 _total_free_4k_blocks_uncertain = false;
2568 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2569 #if defined(__NetBSD__)
2570 struct statvfs statfsbuf;
2572 statvfs (i->path.c_str(), &statfsbuf);
2574 struct statfs statfsbuf;
2576 statfs (i->path.c_str(), &statfsbuf);
2578 double const scale = statfsbuf.f_bsize / 4096.0;
2580 /* See if this filesystem is read-only */
2581 struct statvfs statvfsbuf;
2582 statvfs (i->path.c_str(), &statvfsbuf);
2584 /* f_bavail can be 0 if it is undefined for whatever
2585 filesystem we are looking at; Samba shares mounted
2586 via GVFS are an example of this.
2588 if (statfsbuf.f_bavail == 0) {
2589 /* block count unknown */
2591 i->blocks_unknown = true;
2592 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2593 /* read-only filesystem */
2595 i->blocks_unknown = false;
2597 /* read/write filesystem with known space */
2598 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2599 i->blocks_unknown = false;
2602 _total_free_4k_blocks += i->blocks;
2603 if (i->blocks_unknown) {
2604 _total_free_4k_blocks_uncertain = true;
2607 #elif defined PLATFORM_WINDOWS
2608 vector<string> scanned_volumes;
2609 vector<string>::iterator j;
2610 vector<space_and_path>::iterator i;
2611 DWORD nSectorsPerCluster, nBytesPerSector,
2612 nFreeClusters, nTotalClusters;
2616 _total_free_4k_blocks = 0;
2618 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2619 strncpy (disk_drive, (*i).path.c_str(), 3);
2623 volume_found = false;
2624 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2626 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2627 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2628 i->blocks = (uint32_t)(nFreeBytes / 4096);
2630 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2631 if (0 == j->compare(disk_drive)) {
2632 volume_found = true;
2637 if (!volume_found) {
2638 scanned_volumes.push_back(disk_drive);
2639 _total_free_4k_blocks += i->blocks;
2644 if (0 == _total_free_4k_blocks) {
2645 strncpy (disk_drive, path().c_str(), 3);
2648 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2650 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2651 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2652 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2659 Session::get_best_session_directory_for_new_audio ()
2661 vector<space_and_path>::iterator i;
2662 string result = _session_dir->root_path();
2664 /* handle common case without system calls */
2666 if (session_dirs.size() == 1) {
2670 /* OK, here's the algorithm we're following here:
2672 We want to select which directory to use for
2673 the next file source to be created. Ideally,
2674 we'd like to use a round-robin process so as to
2675 get maximum performance benefits from splitting
2676 the files across multiple disks.
2678 However, in situations without much diskspace, an
2679 RR approach may end up filling up a filesystem
2680 with new files while others still have space.
2681 Its therefore important to pay some attention to
2682 the freespace in the filesystem holding each
2683 directory as well. However, if we did that by
2684 itself, we'd keep creating new files in the file
2685 system with the most space until it was as full
2686 as all others, thus negating any performance
2687 benefits of this RAID-1 like approach.
2689 So, we use a user-configurable space threshold. If
2690 there are at least 2 filesystems with more than this
2691 much space available, we use RR selection between them.
2692 If not, then we pick the filesystem with the most space.
2694 This gets a good balance between the two
2698 refresh_disk_space ();
2700 int free_enough = 0;
2702 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2703 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2708 if (free_enough >= 2) {
2709 /* use RR selection process, ensuring that the one
2713 i = last_rr_session_dir;
2716 if (++i == session_dirs.end()) {
2717 i = session_dirs.begin();
2720 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2721 SessionDirectory sdir(i->path);
2722 if (sdir.create ()) {
2724 last_rr_session_dir = i;
2729 } while (i != last_rr_session_dir);
2733 /* pick FS with the most freespace (and that
2734 seems to actually work ...)
2737 vector<space_and_path> sorted;
2738 space_and_path_ascending_cmp cmp;
2740 sorted = session_dirs;
2741 sort (sorted.begin(), sorted.end(), cmp);
2743 for (i = sorted.begin(); i != sorted.end(); ++i) {
2744 SessionDirectory sdir(i->path);
2745 if (sdir.create ()) {
2747 last_rr_session_dir = i;
2757 Session::automation_dir () const
2759 return Glib::build_filename (_path, automation_dir_name);
2763 Session::analysis_dir () const
2765 return Glib::build_filename (_path, analysis_dir_name);
2769 Session::plugins_dir () const
2771 return Glib::build_filename (_path, plugins_dir_name);
2775 Session::externals_dir () const
2777 return Glib::build_filename (_path, externals_dir_name);
2781 Session::load_bundles (XMLNode const & node)
2783 XMLNodeList nlist = node.children();
2784 XMLNodeConstIterator niter;
2788 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2789 if ((*niter)->name() == "InputBundle") {
2790 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2791 } else if ((*niter)->name() == "OutputBundle") {
2792 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2794 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2803 Session::load_route_groups (const XMLNode& node, int version)
2805 XMLNodeList nlist = node.children();
2806 XMLNodeConstIterator niter;
2810 if (version >= 3000) {
2812 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2813 if ((*niter)->name() == "RouteGroup") {
2814 RouteGroup* rg = new RouteGroup (*this, "");
2815 add_route_group (rg);
2816 rg->set_state (**niter, version);
2820 } else if (version < 3000) {
2822 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2823 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2824 RouteGroup* rg = new RouteGroup (*this, "");
2825 add_route_group (rg);
2826 rg->set_state (**niter, version);
2835 state_file_filter (const string &str, void* /*arg*/)
2837 return (str.length() > strlen(statefile_suffix) &&
2838 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2842 remove_end(string state)
2844 string statename(state);
2846 string::size_type start,end;
2847 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2848 statename = statename.substr (start+1);
2851 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2852 end = statename.length();
2855 return string(statename.substr (0, end));
2859 Session::possible_states (string path)
2861 vector<string> states;
2862 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2864 transform(states.begin(), states.end(), states.begin(), remove_end);
2866 sort (states.begin(), states.end());
2872 Session::possible_states () const
2874 return possible_states(_path);
2878 Session::new_route_group (const std::string& name)
2880 RouteGroup* rg = NULL;
2882 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2883 if ((*i)->name () == name) {
2890 rg = new RouteGroup (*this, name);
2891 add_route_group (rg);
2897 Session::add_route_group (RouteGroup* g)
2899 _route_groups.push_back (g);
2900 route_group_added (g); /* EMIT SIGNAL */
2902 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2903 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2904 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2910 Session::remove_route_group (RouteGroup& rg)
2912 list<RouteGroup*>::iterator i;
2914 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2915 _route_groups.erase (i);
2918 route_group_removed (); /* EMIT SIGNAL */
2922 /** Set a new order for our route groups, without adding or removing any.
2923 * @param groups Route group list in the new order.
2926 Session::reorder_route_groups (list<RouteGroup*> groups)
2928 _route_groups = groups;
2930 route_groups_reordered (); /* EMIT SIGNAL */
2936 Session::route_group_by_name (string name)
2938 list<RouteGroup *>::iterator i;
2940 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2941 if ((*i)->name() == name) {
2949 Session::all_route_group() const
2951 return *_all_route_group;
2955 Session::add_commands (vector<Command*> const & cmds)
2957 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2963 Session::add_command (Command* const cmd)
2965 assert (_current_trans);
2966 DEBUG_UNDO_HISTORY (
2967 string_compose ("Current Undo Transaction %1, adding command: %2",
2968 _current_trans->name (),
2970 _current_trans->add_command (cmd);
2973 PBD::StatefulDiffCommand*
2974 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2976 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2982 Session::begin_reversible_command (const string& name)
2984 begin_reversible_command (g_quark_from_string (name.c_str ()));
2987 /** Begin a reversible command using a GQuark to identify it.
2988 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2989 * but there must be as many begin...()s as there are commit...()s.
2992 Session::begin_reversible_command (GQuark q)
2994 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2995 to hold all the commands that are committed. This keeps the order of
2996 commands correct in the history.
2999 if (_current_trans == 0) {
3000 DEBUG_UNDO_HISTORY (string_compose (
3001 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
3003 /* start a new transaction */
3004 assert (_current_trans_quarks.empty ());
3005 _current_trans = new UndoTransaction();
3006 _current_trans->set_name (g_quark_to_string (q));
3008 DEBUG_UNDO_HISTORY (
3009 string_compose ("Begin Reversible Command, current transaction: %1",
3010 _current_trans->name ()));
3013 _current_trans_quarks.push_front (q);
3017 Session::abort_reversible_command ()
3019 if (_current_trans != 0) {
3020 DEBUG_UNDO_HISTORY (
3021 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
3022 _current_trans->clear();
3023 delete _current_trans;
3025 _current_trans_quarks.clear();
3030 Session::commit_reversible_command (Command *cmd)
3032 assert (_current_trans);
3033 assert (!_current_trans_quarks.empty ());
3038 DEBUG_UNDO_HISTORY (
3039 string_compose ("Current Undo Transaction %1, adding command: %2",
3040 _current_trans->name (),
3042 _current_trans->add_command (cmd);
3045 DEBUG_UNDO_HISTORY (
3046 string_compose ("Commit Reversible Command, current transaction: %1",
3047 _current_trans->name ()));
3049 _current_trans_quarks.pop_front ();
3051 if (!_current_trans_quarks.empty ()) {
3052 DEBUG_UNDO_HISTORY (
3053 string_compose ("Commit Reversible Command, transaction is not "
3054 "top-level, current transaction: %1",
3055 _current_trans->name ()));
3056 /* the transaction we're committing is not the top-level one */
3060 if (_current_trans->empty()) {
3061 /* no commands were added to the transaction, so just get rid of it */
3062 DEBUG_UNDO_HISTORY (
3063 string_compose ("Commit Reversible Command, No commands were "
3064 "added to current transaction: %1",
3065 _current_trans->name ()));
3066 delete _current_trans;
3071 gettimeofday (&now, 0);
3072 _current_trans->set_timestamp (now);
3074 _history.add (_current_trans);
3079 accept_all_audio_files (const string& path, void* /*arg*/)
3081 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3085 if (!AudioFileSource::safe_audio_file_extension (path)) {
3093 accept_all_midi_files (const string& path, void* /*arg*/)
3095 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3099 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3100 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3101 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3105 accept_all_state_files (const string& path, void* /*arg*/)
3107 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3111 std::string const statefile_ext (statefile_suffix);
3112 if (path.length() >= statefile_ext.length()) {
3113 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3120 Session::find_all_sources (string path, set<string>& result)
3125 if (!tree.read (path)) {
3129 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3134 XMLNodeConstIterator niter;
3136 nlist = node->children();
3140 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3142 XMLProperty const * prop;
3144 if ((prop = (*niter)->property (X_("type"))) == 0) {
3148 DataType type (prop->value());
3150 if ((prop = (*niter)->property (X_("name"))) == 0) {
3154 if (Glib::path_is_absolute (prop->value())) {
3155 /* external file, ignore */
3163 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3164 result.insert (found_path);
3172 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3174 vector<string> state_files;
3176 string this_snapshot_path;
3182 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3183 ripped = ripped.substr (0, ripped.length() - 1);
3186 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3188 if (state_files.empty()) {
3193 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3194 this_snapshot_path += statefile_suffix;
3196 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3198 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3200 if (exclude_this_snapshot && *i == this_snapshot_path) {
3201 cerr << "\texcluded\n";
3206 if (find_all_sources (*i, result) < 0) {
3214 struct RegionCounter {
3215 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3216 AudioSourceList::iterator iter;
3217 boost::shared_ptr<Region> region;
3220 RegionCounter() : count (0) {}
3224 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3226 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3227 return r.get_value_or (1);
3231 Session::cleanup_regions ()
3233 bool removed = false;
3234 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3236 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3238 uint32_t used = playlists->region_use_count (i->second);
3240 if (used == 0 && !i->second->automatic ()) {
3241 boost::weak_ptr<Region> w = i->second;
3244 RegionFactory::map_remove (w);
3251 // re-check to remove parent references of compound regions
3252 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3253 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3257 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3258 if (0 == playlists->region_use_count (i->second)) {
3259 boost::weak_ptr<Region> w = i->second;
3261 RegionFactory::map_remove (w);
3268 /* dump the history list */
3275 Session::can_cleanup_peakfiles () const
3277 if (deletion_in_progress()) {
3280 if (!_writable || (_state_of_the_state & CannotSave)) {
3281 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3284 if (record_status() == Recording) {
3285 error << _("Cannot cleanup peak-files while recording") << endmsg;
3292 Session::cleanup_peakfiles ()
3294 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3299 assert (can_cleanup_peakfiles ());
3300 assert (!peaks_cleanup_in_progres());
3302 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3304 int timeout = 5000; // 5 seconds
3305 while (!SourceFactory::files_with_peaks.empty()) {
3306 Glib::usleep (1000);
3307 if (--timeout < 0) {
3308 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3309 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3314 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3315 boost::shared_ptr<AudioSource> as;
3316 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3317 as->close_peakfile();
3321 PBD::clear_directory (session_directory().peak_path());
3323 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3325 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3326 boost::shared_ptr<AudioSource> as;
3327 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3328 SourceFactory::setup_peakfile(as, true);
3335 Session::cleanup_sources (CleanupReport& rep)
3337 // FIXME: needs adaptation to midi
3339 vector<boost::shared_ptr<Source> > dead_sources;
3342 vector<string> candidates;
3343 vector<string> unused;
3344 set<string> sources_used_by_all_snapshots;
3351 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3353 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3355 /* this is mostly for windows which doesn't allow file
3356 * renaming if the file is in use. But we don't special
3357 * case it because we need to know if this causes
3358 * problems, and the easiest way to notice that is to
3359 * keep it in place for all platforms.
3362 request_stop (false);
3364 _butler->wait_until_finished ();
3366 /* consider deleting all unused playlists */
3368 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3373 /* sync the "all regions" property of each playlist with its current state */
3375 playlists->sync_all_regions_with_regions ();
3377 /* find all un-used sources */
3382 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3384 SourceMap::iterator tmp;
3389 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3393 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3394 dead_sources.push_back (i->second);
3395 i->second->drop_references ();
3401 /* build a list of all the possible audio directories for the session */
3403 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3404 SessionDirectory sdir ((*i).path);
3405 asp += sdir.sound_path();
3407 audio_path += asp.to_string();
3410 /* build a list of all the possible midi directories for the session */
3412 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3413 SessionDirectory sdir ((*i).path);
3414 msp += sdir.midi_path();
3416 midi_path += msp.to_string();
3418 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3419 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3421 /* add sources from all other snapshots as "used", but don't use this
3422 snapshot because the state file on disk still references sources we
3423 may have already dropped.
3426 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3428 /* Although the region factory has a list of all regions ever created
3429 * for this session, we're only interested in regions actually in
3430 * playlists right now. So merge all playlist regions lists together.
3432 * This will include the playlists used within compound regions.
3435 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3437 /* add our current source list
3440 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3441 boost::shared_ptr<FileSource> fs;
3442 SourceMap::iterator tmp = i;
3445 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3451 /* this is mostly for windows which doesn't allow file
3452 * renaming if the file is in use. But we do not special
3453 * case it because we need to know if this causes
3454 * problems, and the easiest way to notice that is to
3455 * keep it in place for all platforms.
3460 if (!fs->is_stub()) {
3462 /* Note that we're checking a list of all
3463 * sources across all snapshots with the list
3464 * of sources used by this snapshot.
3467 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3468 /* this source is in use by this snapshot */
3469 sources_used_by_all_snapshots.insert (fs->path());
3470 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3472 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3473 /* this source is NOT in use by this snapshot */
3475 /* remove all related regions from RegionFactory master list */
3477 RegionFactory::remove_regions_using_source (i->second);
3479 /* remove from our current source list
3480 * also. We may not remove it from
3481 * disk, because it may be used by
3482 * other snapshots, but it isn't used inside this
3483 * snapshot anymore, so we don't need a
3494 /* now check each candidate source to see if it exists in the list of
3495 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3498 cerr << "Candidates: " << candidates.size() << endl;
3499 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3501 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3506 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3508 tmppath1 = canonical_path (spath);
3509 tmppath2 = canonical_path ((*i));
3511 cerr << "\t => " << tmppath2 << endl;
3513 if (tmppath1 == tmppath2) {
3520 unused.push_back (spath);
3524 cerr << "Actually unused: " << unused.size() << endl;
3526 if (unused.empty()) {
3532 /* now try to move all unused files into the "dead" directory(ies) */
3534 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3539 /* don't move the file across filesystems, just
3540 * stick it in the `dead_dir_name' directory
3541 * on whichever filesystem it was already on.
3544 if ((*x).find ("/sounds/") != string::npos) {
3546 /* old school, go up 1 level */
3548 newpath = Glib::path_get_dirname (*x); // "sounds"
3549 newpath = Glib::path_get_dirname (newpath); // "session-name"
3553 /* new school, go up 4 levels */
3555 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3556 newpath = Glib::path_get_dirname (newpath); // "session-name"
3557 newpath = Glib::path_get_dirname (newpath); // "interchange"
3558 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3561 newpath = Glib::build_filename (newpath, dead_dir_name);
3563 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3564 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3568 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3570 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3572 /* the new path already exists, try versioning */
3574 char buf[PATH_MAX+1];
3578 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3581 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3582 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3586 if (version == 999) {
3587 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3591 newpath = newpath_v;
3596 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3597 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3598 newpath, g_strerror (errno)) << endmsg;
3602 /* see if there an easy to find peakfile for this file, and remove it. */
3604 string base = Glib::path_get_basename (*x);
3605 base += "%A"; /* this is what we add for the channel suffix of all native files,
3606 * or for the first channel of embedded files. it will miss
3607 * some peakfiles for other channels
3609 string peakpath = construct_peak_filepath (base);
3611 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3612 if (::g_unlink (peakpath.c_str ()) != 0) {
3613 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3614 g_strerror (errno)) << endmsg;
3615 /* try to back out */
3616 ::g_rename (newpath.c_str (), _path.c_str ());
3621 rep.paths.push_back (*x);
3622 rep.space += statbuf.st_size;
3625 /* dump the history list */
3629 /* save state so we don't end up a session file
3630 * referring to non-existent sources.
3637 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3643 Session::cleanup_trash_sources (CleanupReport& rep)
3645 // FIXME: needs adaptation for MIDI
3647 vector<space_and_path>::iterator i;
3653 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3655 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3657 clear_directory (dead_dir, &rep.space, &rep.paths);
3664 Session::set_dirty ()
3666 /* return early if there's nothing to do */
3671 /* never mark session dirty during loading */
3672 if (_state_of_the_state & (Loading | Deletion)) {
3676 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3677 DirtyChanged(); /* EMIT SIGNAL */
3681 Session::set_clean ()
3683 bool was_dirty = dirty();
3685 _state_of_the_state = Clean;
3688 DirtyChanged(); /* EMIT SIGNAL */
3693 Session::set_deletion_in_progress ()
3695 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3699 Session::clear_deletion_in_progress ()
3701 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3705 Session::add_controllable (boost::shared_ptr<Controllable> c)
3707 /* this adds a controllable to the list managed by the Session.
3708 this is a subset of those managed by the Controllable class
3709 itself, and represents the only ones whose state will be saved
3710 as part of the session.
3713 Glib::Threads::Mutex::Lock lm (controllables_lock);
3714 controllables.insert (c);
3717 struct null_deleter { void operator()(void const *) const {} };
3720 Session::remove_controllable (Controllable* c)
3722 if (_state_of_the_state & Deletion) {
3726 Glib::Threads::Mutex::Lock lm (controllables_lock);
3728 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3730 if (x != controllables.end()) {
3731 controllables.erase (x);
3735 boost::shared_ptr<Controllable>
3736 Session::controllable_by_id (const PBD::ID& id)
3738 Glib::Threads::Mutex::Lock lm (controllables_lock);
3740 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3741 if ((*i)->id() == id) {
3746 return boost::shared_ptr<Controllable>();
3749 boost::shared_ptr<AutomationControl>
3750 Session::automation_control_by_id (const PBD::ID& id)
3752 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3756 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3759 Stateful::add_instant_xml (node, _path);
3762 if (write_to_config) {
3763 Config->add_instant_xml (node);
3768 Session::instant_xml (const string& node_name)
3770 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3771 if (get_disable_all_loaded_plugins ()) {
3775 return Stateful::instant_xml (node_name, _path);
3779 Session::save_history (string snapshot_name)
3787 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3788 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3792 if (snapshot_name.empty()) {
3793 snapshot_name = _current_snapshot_name;
3796 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3797 const string backup_filename = history_filename + backup_suffix;
3798 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3799 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3801 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3802 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3803 error << _("could not backup old history file, current history not saved") << endmsg;
3808 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3810 if (!tree.write (xml_path))
3812 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3814 if (g_remove (xml_path.c_str()) != 0) {
3815 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3816 xml_path, g_strerror (errno)) << endmsg;
3818 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3819 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3820 backup_path, g_strerror (errno)) << endmsg;
3830 Session::restore_history (string snapshot_name)
3834 if (snapshot_name.empty()) {
3835 snapshot_name = _current_snapshot_name;
3838 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3839 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3841 info << "Loading history from " << xml_path << endmsg;
3843 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3844 info << string_compose (_("%1: no history file \"%2\" for this session."),
3845 _name, xml_path) << endmsg;
3849 if (!tree.read (xml_path)) {
3850 error << string_compose (_("Could not understand session history file \"%1\""),
3851 xml_path) << endmsg;
3858 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3866 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3867 !t->get_property ("tv-usec", tv_usec)) {
3871 UndoTransaction* ut = new UndoTransaction ();
3872 ut->set_name (name);
3876 tv.tv_usec = tv_usec;
3877 ut->set_timestamp(tv);
3879 for (XMLNodeConstIterator child_it = t->children().begin();
3880 child_it != t->children().end(); child_it++)
3882 XMLNode *n = *child_it;
3885 if (n->name() == "MementoCommand" ||
3886 n->name() == "MementoUndoCommand" ||
3887 n->name() == "MementoRedoCommand") {
3889 if ((c = memento_command_factory(n))) {
3893 } else if (n->name() == "NoteDiffCommand") {
3894 PBD::ID id (n->property("midi-source")->value());
3895 boost::shared_ptr<MidiSource> midi_source =
3896 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3898 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3900 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3903 } else if (n->name() == "SysExDiffCommand") {
3905 PBD::ID id (n->property("midi-source")->value());
3906 boost::shared_ptr<MidiSource> midi_source =
3907 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3909 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3911 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3914 } else if (n->name() == "PatchChangeDiffCommand") {
3916 PBD::ID id (n->property("midi-source")->value());
3917 boost::shared_ptr<MidiSource> midi_source =
3918 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3920 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3922 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3925 } else if (n->name() == "StatefulDiffCommand") {
3926 if ((c = stateful_diff_command_factory (n))) {
3927 ut->add_command (c);
3930 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3941 Session::config_changed (std::string p, bool ours)
3947 if (p == "auto-loop") {
3949 } else if (p == "session-monitoring") {
3951 } else if (p == "auto-input") {
3953 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3954 /* auto-input only makes a difference if we're rolling */
3955 set_track_monitor_input_status (!config.get_auto_input());
3958 } else if (p == "punch-in") {
3962 if ((location = _locations->auto_punch_location()) != 0) {
3964 if (config.get_punch_in ()) {
3965 auto_punch_start_changed (location);
3967 clear_events (SessionEvent::PunchIn);
3971 } else if (p == "punch-out") {
3975 if ((location = _locations->auto_punch_location()) != 0) {
3977 if (config.get_punch_out()) {
3978 auto_punch_end_changed (location);
3980 clear_events (SessionEvent::PunchOut);
3984 } else if (p == "edit-mode") {
3986 Glib::Threads::Mutex::Lock lm (playlists->lock);
3988 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3989 (*i)->set_edit_mode (Config->get_edit_mode ());
3992 } else if (p == "use-video-sync") {
3994 waiting_for_sync_offset = config.get_use_video_sync();
3996 } else if (p == "mmc-control") {
3998 //poke_midi_thread ();
4000 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4002 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4004 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4006 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4008 } else if (p == "midi-control") {
4010 //poke_midi_thread ();
4012 } else if (p == "raid-path") {
4014 setup_raid_path (config.get_raid_path());
4016 } else if (p == "timecode-format") {
4020 } else if (p == "video-pullup") {
4024 } else if (p == "seamless-loop") {
4026 if (play_loop && transport_rolling()) {
4027 // to reset diskstreams etc
4028 request_play_loop (true);
4031 } else if (p == "rf-speed") {
4033 cumulative_rf_motion = 0;
4036 } else if (p == "click-sound") {
4038 setup_click_sounds (1);
4040 } else if (p == "click-emphasis-sound") {
4042 setup_click_sounds (-1);
4044 } else if (p == "clicking") {
4046 if (Config->get_clicking()) {
4047 if (_click_io && click_data) { // don't require emphasis data
4054 } else if (p == "click-record-only") {
4056 _click_rec_only = Config->get_click_record_only();
4058 } else if (p == "click-gain") {
4061 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4064 } else if (p == "send-mtc") {
4066 if (Config->get_send_mtc ()) {
4067 /* mark us ready to send */
4068 next_quarter_frame_to_send = 0;
4071 } else if (p == "send-mmc") {
4073 _mmc->enable_send (Config->get_send_mmc ());
4074 if (Config->get_send_mmc ()) {
4075 /* re-initialize MMC */
4076 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4077 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4080 } else if (p == "jack-time-master") {
4082 engine().reset_timebase ();
4084 } else if (p == "native-file-header-format") {
4086 if (!first_file_header_format_reset) {
4087 reset_native_file_format ();
4090 first_file_header_format_reset = false;
4092 } else if (p == "native-file-data-format") {
4094 if (!first_file_data_format_reset) {
4095 reset_native_file_format ();
4098 first_file_data_format_reset = false;
4100 } else if (p == "external-sync") {
4101 request_sync_source (TransportMasterManager::instance().current());
4102 } else if (p == "denormal-model") {
4104 } else if (p == "history-depth") {
4105 set_history_depth (Config->get_history_depth());
4106 } else if (p == "remote-model") {
4107 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4110 } else if (p == "initial-program-change") {
4112 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4115 buf[0] = MIDI::program; // channel zero by default
4116 buf[1] = (Config->get_initial_program_change() & 0x7f);
4118 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4120 } else if (p == "solo-mute-override") {
4121 // catch_up_on_solo_mute_override ();
4122 } else if (p == "listen-position" || p == "pfl-position") {
4123 listen_position_changed ();
4124 } else if (p == "solo-control-is-listen-control") {
4125 solo_control_mode_changed ();
4126 } else if (p == "solo-mute-gain") {
4127 _solo_cut_control->Changed (true, Controllable::NoGroup);
4128 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4129 last_timecode_valid = false;
4130 } else if (p == "playback-buffer-seconds") {
4131 AudioSource::allocate_working_buffers (sample_rate());
4132 } else if (p == "ltc-sink-port") {
4133 reconnect_ltc_output ();
4134 } else if (p == "timecode-generator-offset") {
4135 ltc_tx_parse_offset();
4136 } else if (p == "auto-return-target-list") {
4137 follow_playhead_priority ();
4138 } else if (p == "use-monitor-bus") {
4139 bool yn = Config->get_use_monitor_bus();
4140 if (yn && !_monitor_out) {
4141 add_monitor_section ();
4142 } else if (!yn && _monitor_out) {
4143 remove_monitor_section ();
4151 Session::set_history_depth (uint32_t d)
4153 _history.set_depth (d);
4156 /** Connect things to the MMC object */
4158 Session::setup_midi_machine_control ()
4160 _mmc = new MIDI::MachineControl;
4162 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4163 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4165 if (!async_out || !async_out) {
4169 /* XXXX argh, passing raw pointers back into libmidi++ */
4171 MIDI::Port* mmc_in = async_in.get();
4172 MIDI::Port* mmc_out = async_out.get();
4174 _mmc->set_ports (mmc_in, mmc_out);
4176 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4177 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4178 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4179 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4180 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4181 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4182 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4183 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4184 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4185 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4186 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4187 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4188 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4190 /* also handle MIDI SPP because its so common */
4192 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4193 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4194 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4197 boost::shared_ptr<Controllable>
4198 Session::solo_cut_control() const
4200 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4201 * controls in Ardour that currently get presented to the user in the GUI that require
4202 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4204 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4205 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4208 return _solo_cut_control;
4212 Session::save_snapshot_name (const std::string & n)
4214 /* assure Stateful::_instant_xml is loaded
4215 * add_instant_xml() only adds to existing data and defaults
4216 * to use an empty Tree otherwise
4218 instant_xml ("LastUsedSnapshot");
4220 XMLNode last_used_snapshot ("LastUsedSnapshot");
4221 last_used_snapshot.set_property ("name", n);
4222 add_instant_xml (last_used_snapshot, false);
4226 Session::set_snapshot_name (const std::string & n)
4228 _current_snapshot_name = n;
4229 save_snapshot_name (n);
4233 Session::rename (const std::string& new_name)
4235 string legal_name = legalize_for_path (new_name);
4241 string const old_sources_root = _session_dir->sources_root();
4243 if (!_writable || (_state_of_the_state & CannotSave)) {
4244 error << _("Cannot rename read-only session.") << endmsg;
4245 return 0; // don't show "messed up" warning
4247 if (record_status() == Recording) {
4248 error << _("Cannot rename session while recording") << endmsg;
4249 return 0; // don't show "messed up" warning
4252 StateProtector stp (this);
4257 * interchange subdirectory
4261 * Backup files are left unchanged and not renamed.
4264 /* Windows requires that we close all files before attempting the
4265 * rename. This works on other platforms, but isn't necessary there.
4266 * Leave it in place for all platforms though, since it may help
4267 * catch issues that could arise if the way Source files work ever
4268 * change (since most developers are not using Windows).
4271 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4272 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4278 /* pass one: not 100% safe check that the new directory names don't
4282 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4286 /* this is a stupid hack because Glib::path_get_dirname() is
4287 * lexical-only, and so passing it /a/b/c/ gives a different
4288 * result than passing it /a/b/c ...
4291 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4292 oldstr = oldstr.substr (0, oldstr.length() - 1);
4295 string base = Glib::path_get_dirname (oldstr);
4297 newstr = Glib::build_filename (base, legal_name);
4299 cerr << "Looking for " << newstr << endl;
4301 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4302 cerr << " exists\n";
4311 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4317 /* this is a stupid hack because Glib::path_get_dirname() is
4318 * lexical-only, and so passing it /a/b/c/ gives a different
4319 * result than passing it /a/b/c ...
4322 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4323 oldstr = oldstr.substr (0, oldstr.length() - 1);
4326 string base = Glib::path_get_dirname (oldstr);
4327 newstr = Glib::build_filename (base, legal_name);
4329 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4331 cerr << "Rename " << oldstr << " => " << newstr << endl;
4332 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4333 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4334 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4338 /* Reset path in "session dirs" */
4343 /* reset primary SessionDirectory object */
4346 (*_session_dir) = newstr;
4351 /* now rename directory below session_dir/interchange */
4353 string old_interchange_dir;
4354 string new_interchange_dir;
4356 /* use newstr here because we renamed the path
4357 * (folder/directory) that used to be oldstr to newstr above
4360 v.push_back (newstr);
4361 v.push_back (interchange_dir_name);
4362 v.push_back (Glib::path_get_basename (oldstr));
4364 old_interchange_dir = Glib::build_filename (v);
4367 v.push_back (newstr);
4368 v.push_back (interchange_dir_name);
4369 v.push_back (legal_name);
4371 new_interchange_dir = Glib::build_filename (v);
4373 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4375 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4376 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4377 old_interchange_dir, new_interchange_dir,
4380 error << string_compose (_("renaming %s as %2 failed (%3)"),
4381 old_interchange_dir, new_interchange_dir,
4390 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4391 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4393 cerr << "Rename " << oldstr << " => " << newstr << endl;
4395 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4396 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4397 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4403 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4405 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4406 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4408 cerr << "Rename " << oldstr << " => " << newstr << endl;
4410 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4411 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4412 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4417 /* remove old name from recent sessions */
4418 remove_recent_sessions (_path);
4421 /* update file source paths */
4423 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4424 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4426 string p = fs->path ();
4427 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4429 SourceFactory::setup_peakfile(i->second, true);
4433 set_snapshot_name (new_name);
4438 /* save state again to get everything just right */
4440 save_state (_current_snapshot_name);
4442 /* add to recent sessions */
4444 store_recent_sessions (new_name, _path);
4450 Session::parse_stateful_loading_version (const std::string& version)
4452 if (version.empty ()) {
4453 /* no version implies very old version of Ardour */
4457 if (version.find ('.') != string::npos) {
4458 /* old school version format */
4459 if (version[0] == '2') {
4465 return string_to<int32_t>(version);
4470 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4472 bool found_sr = false;
4473 bool found_data_format = false;
4474 std::string version;
4475 program_version = "";
4477 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4481 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4485 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4488 xmlFreeParserCtxt(ctxt);
4492 xmlNodePtr node = xmlDocGetRootElement(doc);
4495 xmlFreeParserCtxt(ctxt);
4500 /* sample rate & version*/
4503 for (attr = node->properties; attr; attr = attr->next) {
4504 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4505 version = std::string ((char*)attr->children->content);
4507 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4508 sample_rate = atoi ((char*)attr->children->content);
4513 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4517 node = node->children;
4518 while (node != NULL) {
4519 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4520 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4522 program_version = string ((const char*)val);
4523 size_t sep = program_version.find_first_of("-");
4524 if (sep != string::npos) {
4525 program_version = program_version.substr (0, sep);
4530 if (strcmp((const char*) node->name, "Config")) {
4534 for (node = node->children; node; node = node->next) {
4535 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4536 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4538 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4541 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4543 found_data_format = true;
4544 } catch (PBD::unknown_enumeration& e) {}
4554 xmlFreeParserCtxt(ctxt);
4557 return (found_sr && found_data_format) ? 0 : 1;
4561 Session::get_snapshot_from_instant (const std::string& session_dir)
4563 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4565 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4570 if (!tree.read (instant_xml_path)) {
4574 XMLProperty const * prop;
4575 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4576 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4577 return prop->value();
4583 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4584 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4587 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4591 SourcePathMap source_path_map;
4593 boost::shared_ptr<AudioFileSource> afs;
4598 Glib::Threads::Mutex::Lock lm (source_lock);
4600 cerr << " total sources = " << sources.size();
4602 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4603 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4609 if (fs->within_session()) {
4613 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4614 source_path_map[fs->path()].push_back (fs);
4616 SeveralFileSources v;
4618 source_path_map.insert (make_pair (fs->path(), v));
4624 cerr << " fsources = " << total << endl;
4626 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4628 /* tell caller where we are */
4630 string old_path = i->first;
4632 callback (n, total, old_path);
4634 cerr << old_path << endl;
4638 switch (i->second.front()->type()) {
4639 case DataType::AUDIO:
4640 new_path = new_audio_source_path_for_embedded (old_path);
4643 case DataType::MIDI:
4644 /* XXX not implemented yet */
4648 if (new_path.empty()) {
4652 cerr << "Move " << old_path << " => " << new_path << endl;
4654 if (!copy_file (old_path, new_path)) {
4655 cerr << "failed !\n";
4659 /* make sure we stop looking in the external
4660 dir/folder. Remember, this is an all-or-nothing
4661 operations, it doesn't merge just some files.
4663 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4665 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4666 (*f)->set_path (new_path);
4671 save_state ("", false, false);
4677 bool accept_all_files (string const &, void *)
4683 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4685 /* 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.
4690 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4692 // old_path must be in within_session ()
4693 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4695 v.push_back (new_session_folder); /* full path */
4696 v.push_back (interchange_dir_name);
4697 v.push_back (new_session_name); /* just one directory/folder */
4698 v.push_back (typedir);
4699 v.push_back (Glib::path_get_basename (old_path));
4701 return Glib::build_filename (v);
4705 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4708 v.push_back (new_session_folder); /* full path */
4709 v.push_back (interchange_dir_name);
4710 v.push_back (new_session_name);
4711 v.push_back (ARDOUR::sound_dir_name);
4712 v.push_back (filename);
4714 return Glib::build_filename (v);
4718 Session::save_as (SaveAs& saveas)
4720 vector<string> files;
4721 string current_folder = Glib::path_get_dirname (_path);
4722 string new_folder = legalize_for_path (saveas.new_name);
4723 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4724 int64_t total_bytes = 0;
4728 int32_t internal_file_cnt = 0;
4730 vector<string> do_not_copy_extensions;
4731 do_not_copy_extensions.push_back (statefile_suffix);
4732 do_not_copy_extensions.push_back (pending_suffix);
4733 do_not_copy_extensions.push_back (backup_suffix);
4734 do_not_copy_extensions.push_back (temp_suffix);
4735 do_not_copy_extensions.push_back (history_suffix);
4737 /* get total size */
4739 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4741 /* need to clear this because
4742 * find_files_matching_filter() is cumulative
4747 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4749 all += files.size();
4751 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4753 g_stat ((*i).c_str(), &gsb);
4754 total_bytes += gsb.st_size;
4758 /* save old values so we can switch back if we are not switching to the new session */
4760 string old_path = _path;
4761 string old_name = _name;
4762 string old_snapshot = _current_snapshot_name;
4763 string old_sd = _session_dir->root_path();
4764 vector<string> old_search_path[DataType::num_types];
4765 string old_config_search_path[DataType::num_types];
4767 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4768 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4769 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4770 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4772 /* switch session directory */
4774 (*_session_dir) = to_dir;
4776 /* create new tree */
4778 if (!_session_dir->create()) {
4779 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4784 /* copy all relevant files. Find each location in session_dirs,
4785 * and copy files from there to target.
4788 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4790 /* need to clear this because
4791 * find_files_matching_filter() is cumulative
4796 const size_t prefix_len = (*sd).path.size();
4798 /* Work just on the files within this session dir */
4800 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4802 /* add dir separator to protect against collisions with
4803 * track names (e.g. track named "audiofiles" or
4807 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4808 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4809 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4811 /* copy all the files. Handling is different for media files
4812 than others because of the *silly* subtree we have below the interchange
4813 folder. That really was a bad idea, but I'm not fixing it as part of
4814 implementing ::save_as().
4817 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4819 std::string from = *i;
4822 string filename = Glib::path_get_basename (from);
4823 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4824 if (filename == ".DS_STORE") {
4829 if (from.find (audiofile_dir_string) != string::npos) {
4831 /* audio file: only copy if asked */
4833 if (saveas.include_media && saveas.copy_media) {
4835 string to = make_new_media_path (*i, to_dir, new_folder);
4837 info << "media file copying from " << from << " to " << to << endmsg;
4839 if (!copy_file (from, to)) {
4840 throw Glib::FileError (Glib::FileError::IO_ERROR,
4841 string_compose(_("\ncopying \"%1\" failed !"), from));
4845 /* we found media files inside the session folder */
4847 internal_file_cnt++;
4849 } else if (from.find (midifile_dir_string) != string::npos) {
4851 /* midi file: always copy unless
4852 * creating an empty new session
4855 if (saveas.include_media) {
4857 string to = make_new_media_path (*i, to_dir, new_folder);
4859 info << "media file copying from " << from << " to " << to << endmsg;
4861 if (!copy_file (from, to)) {
4862 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4866 /* we found media files inside the session folder */
4868 internal_file_cnt++;
4870 } else if (from.find (analysis_dir_string) != string::npos) {
4872 /* make sure analysis dir exists in
4873 * new session folder, but we're not
4874 * copying analysis files here, see
4878 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4883 /* normal non-media file. Don't copy state, history, etc.
4886 bool do_copy = true;
4888 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4889 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4890 /* end of filename matches extension, do not copy file */
4896 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4897 /* don't copy peakfiles if
4898 * we're not copying media
4904 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4906 info << "attempting to make directory/folder " << to << endmsg;
4908 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4909 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4912 info << "attempting to copy " << from << " to " << to << endmsg;
4914 if (!copy_file (from, to)) {
4915 throw Glib::FileError (Glib::FileError::IO_ERROR,
4916 string_compose(_("\ncopying \"%1\" failed !"), from));
4921 /* measure file size even if we're not going to copy so that our Progress
4922 signals are correct, since we included these do-not-copy files
4923 in the computation of the total size and file count.
4927 g_stat (from.c_str(), &gsb);
4928 copied += gsb.st_size;
4931 double fraction = (double) copied / total_bytes;
4933 bool keep_going = true;
4935 if (saveas.copy_media) {
4937 /* no need or expectation of this if
4938 * media is not being copied, because
4939 * it will be fast(ish).
4942 /* tell someone "X percent, file M of N"; M is one-based */
4944 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4952 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4958 /* copy optional folders, if any */
4960 string old = plugins_dir ();
4961 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4962 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4963 copy_files (old, newdir);
4966 old = externals_dir ();
4967 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4968 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4969 copy_files (old, newdir);
4972 old = automation_dir ();
4973 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4974 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4975 copy_files (old, newdir);
4978 if (saveas.include_media) {
4980 if (saveas.copy_media) {
4981 #ifndef PLATFORM_WINDOWS
4982 /* There are problems with analysis files on
4983 * Windows, because they used a colon in their
4984 * names as late as 4.0. Colons are not legal
4985 * under Windows even if NTFS allows them.
4987 * This is a tricky problem to solve so for
4988 * just don't copy these files. They will be
4989 * regenerated as-needed anyway, subject to the
4990 * existing issue that the filenames will be
4991 * rejected by Windows, which is a separate
4992 * problem (though related).
4995 /* only needed if we are copying media, since the
4996 * analysis data refers to media data
4999 old = analysis_dir ();
5000 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5001 string newdir = Glib::build_filename (to_dir, "analysis");
5002 copy_files (old, newdir);
5004 #endif /* PLATFORM_WINDOWS */
5009 set_snapshot_name (saveas.new_name);
5010 _name = saveas.new_name;
5012 if (saveas.include_media && !saveas.copy_media) {
5014 /* reset search paths of the new session (which we're pretending to be right now) to
5015 include the original session search path, so we can still find all audio.
5018 if (internal_file_cnt) {
5019 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5020 ensure_search_path_includes (*s, DataType::AUDIO);
5021 cerr << "be sure to include " << *s << " for audio" << endl;
5024 /* we do not do this for MIDI because we copy
5025 all MIDI files if saveas.include_media is
5031 bool was_dirty = dirty ();
5033 save_default_options ();
5035 if (saveas.copy_media && saveas.copy_external) {
5036 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5037 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5041 saveas.final_session_folder_name = _path;
5043 store_recent_sessions (_name, _path);
5045 if (!saveas.switch_to) {
5047 /* save the new state */
5049 save_state ("", false, false, !saveas.include_media);
5051 /* switch back to the way things were */
5055 set_snapshot_name (old_snapshot);
5057 (*_session_dir) = old_sd;
5063 if (internal_file_cnt) {
5064 /* reset these to their original values */
5065 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5066 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5071 /* prune session dirs, and update disk space statistics
5076 session_dirs.clear ();
5077 session_dirs.push_back (sp);
5078 refresh_disk_space ();
5080 _writable = exists_and_writable (_path);
5082 /* ensure that all existing tracks reset their current capture source paths
5084 reset_write_sources (true, true);
5086 /* creating new write sources marks the session as
5087 dirty. If the new session is empty, then
5088 save_state() thinks we're saving a template and will
5089 not mark the session as clean. So do that here,
5090 before we save state.
5093 if (!saveas.include_media) {
5094 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5097 save_state ("", false, false, !saveas.include_media);
5099 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5100 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5103 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5104 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5110 if (fs->within_session()) {
5111 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5112 fs->set_path (newpath);
5117 } catch (Glib::FileError& e) {
5119 saveas.failure_message = e.what();
5121 /* recursively remove all the directories */
5123 remove_directory (to_dir);
5131 saveas.failure_message = _("unknown reason");
5133 /* recursively remove all the directories */
5135 remove_directory (to_dir);
5145 static void set_progress (Progress* p, size_t n, size_t t)
5147 p->set_progress (float (n) / float(t));
5151 Session::archive_session (const std::string& dest,
5152 const std::string& name,
5153 ArchiveEncode compress_audio,
5154 FileArchive::CompressionLevel compression_level,
5155 bool only_used_sources,
5158 if (dest.empty () || name.empty ()) {
5162 /* We are going to temporarily change some source properties,
5163 * don't allow any concurrent saves (periodic or otherwise */
5164 Glib::Threads::Mutex::Lock lm (save_source_lock);
5166 disable_record (false);
5168 /* save current values */
5169 string old_path = _path;
5170 string old_name = _name;
5171 string old_snapshot = _current_snapshot_name;
5172 string old_sd = _session_dir->root_path();
5173 string old_config_search_path[DataType::num_types];
5174 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5175 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5177 /* ensure that session-path is included in search-path */
5179 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5180 if ((*sd).path == old_path) {
5188 /* create temporary dir to save session to */
5189 #ifdef PLATFORM_WINDOWS
5190 char tmp[256] = "C:\\TEMP\\";
5191 GetTempPath (sizeof (tmp), tmp);
5193 char const* tmp = getenv("TMPDIR");
5198 if ((strlen (tmp) + 21) > 1024) {
5203 strcpy (tmptpl, tmp);
5204 strcat (tmptpl, "ardourarchive-XXXXXX");
5205 char* tmpdir = g_mkdtemp (tmptpl);
5211 std::string to_dir = std::string (tmpdir);
5213 /* switch session directory temporarily */
5214 (*_session_dir) = to_dir;
5216 if (!_session_dir->create()) {
5217 (*_session_dir) = old_sd;
5218 remove_directory (to_dir);
5222 /* prepare archive */
5223 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5225 PBD::ScopedConnectionList progress_connection;
5226 PBD::FileArchive ar (archive);
5228 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5231 /* collect files to archive */
5232 std::map<string,string> filemap;
5234 vector<string> do_not_copy_extensions;
5235 do_not_copy_extensions.push_back (statefile_suffix);
5236 do_not_copy_extensions.push_back (pending_suffix);
5237 do_not_copy_extensions.push_back (backup_suffix);
5238 do_not_copy_extensions.push_back (temp_suffix);
5239 do_not_copy_extensions.push_back (history_suffix);
5241 vector<string> blacklist_dirs;
5242 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5243 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5244 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5245 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5246 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5247 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5249 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5250 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5251 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5253 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5254 if (only_used_sources) {
5255 playlists->sync_all_regions_with_regions ();
5256 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5259 /* collect audio sources for this session, calc total size for encoding
5260 * add option to only include *used* sources (see Session::cleanup_sources)
5262 size_t total_size = 0;
5264 Glib::Threads::Mutex::Lock lm (source_lock);
5266 /* build a list of used names */
5267 std::set<std::string> audio_file_names;
5268 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5269 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5272 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5273 if (!afs || afs->readable_length () == 0) {
5276 if (only_used_sources) {
5280 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5284 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5287 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5288 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5291 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5292 if (!afs || afs->readable_length () == 0) {
5296 if (only_used_sources) {
5300 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5305 std::string from = afs->path();
5307 if (compress_audio != NO_ENCODE) {
5308 total_size += afs->readable_length ();
5310 /* copy files as-is */
5311 if (!afs->within_session()) {
5312 string to = Glib::path_get_basename (from);
5314 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5315 * - avoid conflict with files existing in interchange
5316 * - avoid conflict with other embedded sources
5318 if (audio_file_names.find (to) == audio_file_names.end ()) {
5319 // we need a new name, add a '-<num>' before the '.<ext>'
5320 string bn = to.substr (0, to.find_last_of ('.'));
5321 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5322 to = bn + "-1" + ext;
5324 while (audio_file_names.find (to) == audio_file_names.end ()) {
5325 to = bump_name_once (to, '-');
5328 audio_file_names.insert (to);
5329 filemap[from] = make_new_audio_path (to, name, name);
5331 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5333 orig_origin[afs] = afs->origin ();
5334 afs->set_origin ("");
5337 filemap[from] = make_new_media_path (from, name, name);
5344 if (compress_audio != NO_ENCODE) {
5346 progress->set_progress (2); // set to "encoding"
5347 progress->set_progress (0);
5350 Glib::Threads::Mutex::Lock lm (source_lock);
5351 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5352 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5355 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5356 if (!afs || afs->readable_length () == 0) {
5360 if (only_used_sources) {
5364 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5369 orig_sources[afs] = afs->path();
5370 orig_gain[afs] = afs->gain();
5372 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5374 std::string channelsuffix = "";
5375 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5376 /* embedded external multi-channel files are converted to multiple-mono */
5377 channelsuffix = string_compose ("-c%1", afs->channel ());
5379 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5380 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5382 /* avoid name collisions of external files with same name */
5383 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5384 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5386 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5387 new_path = bump_name_once (new_path, '-');
5391 progress->descend ((float)afs->readable_length () / total_size);
5395 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5396 afs->replace_file (new_path);
5397 afs->set_gain (ns->gain(), true);
5400 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5404 progress->ascend ();
5410 progress->set_progress (-1); // set to "archiving"
5411 progress->set_progress (0);
5414 /* index files relevant for this session */
5415 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5416 vector<string> files;
5418 size_t prefix_len = (*sd).path.size();
5419 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5423 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5425 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5426 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5427 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5429 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5430 std::string from = *i;
5433 string filename = Glib::path_get_basename (from);
5434 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5435 if (filename == ".DS_STORE") {
5440 if (from.find (audiofile_dir_string) != string::npos) {
5442 } else if (from.find (midifile_dir_string) != string::npos) {
5443 filemap[from] = make_new_media_path (from, name, name);
5444 } else if (from.find (videofile_dir_string) != string::npos) {
5445 filemap[from] = make_new_media_path (from, name, name);
5447 bool do_copy = true;
5448 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5449 if (from.find (*v) != string::npos) {
5454 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5455 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5462 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5468 /* write session file */
5470 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5472 save_state (name, false, false, false, true, only_used_sources);
5474 save_default_options ();
5476 size_t prefix_len = _path.size();
5477 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5481 /* collect session-state files */
5482 vector<string> files;
5483 do_not_copy_extensions.clear ();
5484 do_not_copy_extensions.push_back (history_suffix);
5486 blacklist_dirs.clear ();
5487 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5489 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5490 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5491 std::string from = *i;
5492 bool do_copy = true;
5493 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5494 if (from.find (*v) != string::npos) {
5499 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5500 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5506 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5510 /* restore original values */
5513 set_snapshot_name (old_snapshot);
5514 (*_session_dir) = old_sd;
5515 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5516 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5518 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5519 i->first->set_origin (i->second);
5521 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5522 i->first->replace_file (i->second);
5524 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5525 i->first->set_gain (i->second, true);
5528 int rv = ar.create (filemap, compression_level);
5529 remove_directory (to_dir);
5535 Session::undo (uint32_t n)
5537 if (actively_recording()) {
5545 Session::redo (uint32_t n)
5547 if (actively_recording()) {