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_is_free); //deprecated, but keep storing this value for compatibility with prior v5.
1212 node->set_property ("session-range-is-free", _session_range_is_free);
1215 /* save the ID counter */
1217 node->set_property ("id-counter", ID::counter());
1219 node->set_property ("name-counter", name_id_counter ());
1221 /* save the event ID counter */
1223 node->set_property ("event-counter", Evoral::event_id_counter());
1225 /* save the VCA counter */
1227 node->set_property ("vca-counter", VCA::get_next_vca_number());
1229 /* various options */
1231 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1232 if (!midi_port_nodes.empty()) {
1233 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1234 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1235 midi_port_stuff->add_child_nocopy (**n);
1237 node->add_child_nocopy (*midi_port_stuff);
1240 XMLNode& cfgxml (config.get_variables ());
1241 if (save_template) {
1242 /* exclude search-paths from template */
1243 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1244 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1245 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1247 node->add_child_nocopy (cfgxml);
1249 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1251 child = node->add_child ("Sources");
1253 if (!save_template) {
1254 Glib::Threads::Mutex::Lock sl (source_lock);
1256 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1258 if (only_used_assets) {
1259 playlists->sync_all_regions_with_regions ();
1260 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1263 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1265 /* Don't save information about non-file Sources, or
1266 * about non-destructive file sources that are empty
1267 * and unused by any regions.
1269 boost::shared_ptr<FileSource> fs;
1271 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1275 if (!fs->destructive()) {
1276 if (fs->empty() && !fs->used()) {
1281 if (only_used_assets) {
1282 /* skip only unused audio files */
1283 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1284 if (afs && !afs->used()) {
1287 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1292 if (snapshot_type != NormalSave && fs->within_session ()) {
1293 /* copy MIDI sources to new file
1295 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1296 * because the GUI (midi_region) has a direct pointer to the midi-model
1297 * of the source, as does UndoTransaction.
1299 * On the upside, .mid files are not kept open. The file is only open
1300 * when reading the model initially and when flushing the model to disk:
1301 * source->session_saved () or export.
1303 * We can change the _path of the existing source under the hood, keeping
1304 * all IDs, references and pointers intact.
1306 boost::shared_ptr<SMFSource> ms;
1307 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1308 const std::string ancestor_name = ms->ancestor_name();
1309 const std::string base = PBD::basename_nosuffix(ancestor_name);
1310 const string path = new_midi_source_path (base, false);
1312 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1313 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1314 Source::Lock lm (ms->mutex());
1316 // TODO special-case empty, removable() files: just create a new removable.
1317 // (load + write flushes the model and creates the file)
1319 ms->load_model (lm);
1321 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1322 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1324 if (snapshot_type == SnapshotKeep) {
1325 /* keep working on current session.
1327 * Save snapshot-state with the original filename.
1328 * Switch to use new path for future saves of the main session.
1330 child->add_child_nocopy (ms->get_state());
1334 * ~SMFSource unlinks removable() files.
1336 std::string npath (ms->path ());
1337 ms->replace_file (newsrc->path ());
1338 newsrc->replace_file (npath);
1340 if (snapshot_type == SwitchToSnapshot) {
1341 /* save and switch to snapshot.
1343 * Leave the old file in place (as is).
1344 * Snapshot uses new source directly
1346 child->add_child_nocopy (ms->get_state());
1353 child->add_child_nocopy (siter->second->get_state());
1357 child = node->add_child ("Regions");
1359 if (!save_template) {
1360 Glib::Threads::Mutex::Lock rl (region_lock);
1362 if (!only_used_assets) {
1363 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1364 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1365 boost::shared_ptr<Region> r = i->second;
1366 /* only store regions not attached to playlists */
1367 if (r->playlist() == 0) {
1368 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1369 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1371 child->add_child_nocopy (r->get_state ());
1377 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1379 if (!cassocs.empty()) {
1380 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1382 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1383 if (i->first->playlist () == 0 && only_used_assets) {
1386 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1387 can->set_property (X_("copy"), i->first->id());
1388 can->set_property (X_("original"), i->second->id());
1389 ca->add_child_nocopy (*can);
1390 /* see above, child is still "Regions" here */
1391 if (i->second->playlist() == 0 && only_used_assets) {
1392 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1393 child->add_child_nocopy (ar->get_basic_state ());
1395 child->add_child_nocopy (ar->get_state ());
1402 if (!save_template) {
1404 node->add_child_nocopy (_selection->get_state());
1407 node->add_child_nocopy (_locations->get_state());
1410 Locations loc (*this);
1411 const bool was_dirty = dirty();
1412 // for a template, just create a new Locations, populate it
1413 // with the default start and end, and get the state for that.
1414 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1415 range->set (max_samplepos, 0);
1417 XMLNode& locations_state = loc.get_state();
1419 if (ARDOUR::Profile->get_trx() && _locations) {
1420 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1421 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1422 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1423 locations_state.add_child_nocopy ((*i)->get_state ());
1427 node->add_child_nocopy (locations_state);
1429 /* adding a location above will have marked the session
1430 * dirty. This is an artifact, so fix it if the session wasn't
1435 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1439 child = node->add_child ("Bundles");
1441 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1442 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1443 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1445 child->add_child_nocopy (b->get_state());
1450 node->add_child_nocopy (_vca_manager->get_state());
1452 child = node->add_child ("Routes");
1454 boost::shared_ptr<RouteList> r = routes.reader ();
1456 route_id_compare cmp;
1457 RouteList xml_node_order (*r);
1458 xml_node_order.sort (cmp);
1460 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1461 if (!(*i)->is_auditioner()) {
1462 if (save_template) {
1463 child->add_child_nocopy ((*i)->get_template());
1465 child->add_child_nocopy ((*i)->get_state());
1471 playlists->add_state (node, save_template, !only_used_assets);
1473 child = node->add_child ("RouteGroups");
1474 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1475 child->add_child_nocopy ((*i)->get_state());
1479 XMLNode* gain_child = node->add_child ("Click");
1480 gain_child->add_child_nocopy (_click_io->get_state ());
1481 gain_child->add_child_nocopy (_click_gain->get_state ());
1485 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1486 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1489 node->add_child_nocopy (_speakers->get_state());
1490 node->add_child_nocopy (_tempo_map->get_state());
1491 node->add_child_nocopy (get_control_protocol_state());
1494 node->add_child_copy (*_extra_xml);
1498 Glib::Threads::Mutex::Lock lm (lua_lock);
1501 luabridge::LuaRef savedstate ((*_lua_save)());
1502 saved = savedstate.cast<std::string>();
1504 lua.collect_garbage ();
1507 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1508 std::string b64s (b64);
1511 XMLNode* script_node = new XMLNode (X_("Script"));
1512 script_node->set_property (X_("lua"), LUA_VERSION);
1513 script_node->add_content (b64s);
1514 node->add_child_nocopy (*script_node);
1521 Session::get_control_protocol_state ()
1523 return ControlProtocolManager::instance().get_state ();
1527 Session::set_state (const XMLNode& node, int version)
1534 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1536 if (node.name() != X_("Session")) {
1537 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1541 node.get_property ("name", _name);
1543 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1545 _nominal_sample_rate = _base_sample_rate;
1547 assert (AudioEngine::instance()->running ());
1548 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1549 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1550 if (r.get_value_or (0)) {
1556 created_with = "unknown";
1557 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1558 child->get_property (X_("created-with"), created_with);
1561 setup_raid_path(_session_dir->root_path());
1563 node.get_property (X_("end-is-free"), _session_range_is_free); //deprectated, but use old values if they are in the config
1565 node.get_property (X_("session-range-is-free"), _session_range_is_free);
1568 if (node.get_property (X_("id-counter"), counter)) {
1569 ID::init_counter (counter);
1571 /* old sessions used a timebased counter, so fake
1572 * the startup ID counter based on a standard
1577 ID::init_counter (now);
1580 if (node.get_property (X_("name-counter"), counter)) {
1581 init_name_id_counter (counter);
1584 if (node.get_property (X_("event-counter"), counter)) {
1585 Evoral::init_event_id_counter (counter);
1588 if (node.get_property (X_("vca-counter"), counter)) {
1589 VCA::set_next_vca_number (counter);
1591 VCA::set_next_vca_number (1);
1594 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1595 _midi_ports->set_midi_port_states (child->children());
1598 IO::disable_connecting ();
1600 Stateful::save_extra_xml (node);
1602 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1603 load_options (*child);
1604 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1605 load_options (*child);
1607 error << _("Session: XML state has no options section") << endmsg;
1610 if (version >= 3000) {
1611 if ((child = find_named_node (node, "Metadata")) == 0) {
1612 warning << _("Session: XML state has no metadata section") << endmsg;
1613 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1618 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1619 _speakers->set_state (*child, version);
1622 if ((child = find_named_node (node, "Sources")) == 0) {
1623 error << _("Session: XML state has no sources section") << endmsg;
1625 } else if (load_sources (*child)) {
1629 if ((child = find_named_node (node, "TempoMap")) == 0) {
1630 error << _("Session: XML state has no Tempo Map section") << endmsg;
1632 } else if (_tempo_map->set_state (*child, version)) {
1636 if ((child = find_named_node (node, "Locations")) == 0) {
1637 error << _("Session: XML state has no locations section") << endmsg;
1639 } else if (_locations->set_state (*child, version)) {
1643 locations_changed ();
1645 if (_session_range_location) {
1646 AudioFileSource::set_header_position_offset (_session_range_location->start());
1649 if ((child = find_named_node (node, "Regions")) == 0) {
1650 error << _("Session: XML state has no Regions section") << endmsg;
1652 } else if (load_regions (*child)) {
1656 if ((child = find_named_node (node, "Playlists")) == 0) {
1657 error << _("Session: XML state has no playlists section") << endmsg;
1659 } else if (playlists->load (*this, *child)) {
1663 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1665 } else if (playlists->load_unused (*this, *child)) {
1669 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1670 if (load_compounds (*child)) {
1675 if (version >= 3000) {
1676 if ((child = find_named_node (node, "Bundles")) == 0) {
1677 warning << _("Session: XML state has no bundles section") << endmsg;
1680 /* We can't load Bundles yet as they need to be able
1681 * to convert from port names to Port objects, which can't happen until
1683 _bundle_xml_node = new XMLNode (*child);
1687 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1688 _vca_manager->set_state (*child, version);
1691 if ((child = find_named_node (node, "Routes")) == 0) {
1692 error << _("Session: XML state has no routes section") << endmsg;
1694 } else if (load_routes (*child, version)) {
1698 /* Now that we have Routes and masters loaded, connect them if appropriate */
1700 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1702 if (version >= 3000) {
1704 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1705 error << _("Session: XML state has no route groups section") << endmsg;
1707 } else if (load_route_groups (*child, version)) {
1711 } else if (version < 3000) {
1713 if ((child = find_named_node (node, "EditGroups")) == 0) {
1714 error << _("Session: XML state has no edit groups section") << endmsg;
1716 } else if (load_route_groups (*child, version)) {
1720 if ((child = find_named_node (node, "MixGroups")) == 0) {
1721 error << _("Session: XML state has no mix groups section") << endmsg;
1723 } else if (load_route_groups (*child, version)) {
1728 if ((child = find_named_node (node, "Click")) == 0) {
1729 warning << _("Session: XML state has no click section") << endmsg;
1730 } else if (_click_io) {
1731 setup_click_state (&node);
1734 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1735 ControlProtocolManager::instance().set_state (*child, 1 /* here: session-specific state */);
1738 if ((child = find_named_node (node, "Script"))) {
1739 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1740 if (!(*n)->is_content ()) { continue; }
1742 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1744 Glib::Threads::Mutex::Lock lm (lua_lock);
1745 (*_lua_load)(std::string ((const char*)buf, size));
1746 } catch (luabridge::LuaException const& e) {
1747 cerr << "LuaException:" << e.what () << endl;
1753 if ((child = find_named_node (node, X_("Selection")))) {
1754 _selection->set_state (*child, version);
1757 update_route_record_state ();
1759 /* here beginneth the second phase ... */
1760 set_snapshot_name (_current_snapshot_name);
1762 StateReady (); /* EMIT SIGNAL */
1775 Session::load_routes (const XMLNode& node, int version)
1778 XMLNodeConstIterator niter;
1779 RouteList new_routes;
1781 nlist = node.children();
1785 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1787 boost::shared_ptr<Route> route;
1789 if (version < 3000) {
1790 route = XMLRouteFactory_2X (**niter, version);
1791 } else if (version < 5000) {
1792 route = XMLRouteFactory_3X (**niter, version);
1794 route = XMLRouteFactory (**niter, version);
1798 error << _("Session: cannot create Route from XML description.") << endmsg;
1802 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1804 new_routes.push_back (route);
1807 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1809 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1811 BootMessage (_("Finished adding tracks/busses"));
1816 boost::shared_ptr<Route>
1817 Session::XMLRouteFactory (const XMLNode& node, int version)
1819 boost::shared_ptr<Route> ret;
1821 if (node.name() != "Route") {
1825 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1828 pl_prop = node.property (X_("midi-playlist"));
1831 DataType type = DataType::AUDIO;
1832 node.get_property("default-type", type);
1834 assert (type != DataType::NIL);
1838 /* has at least 1 playlist, therefore a track ... */
1840 boost::shared_ptr<Track> track;
1842 if (type == DataType::AUDIO) {
1843 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1845 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1848 if (track->init()) {
1852 if (track->set_state (node, version)) {
1856 BOOST_MARK_TRACK (track);
1860 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1861 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1864 if (r->init () == 0 && r->set_state (node, version) == 0) {
1865 BOOST_MARK_ROUTE (r);
1873 boost::shared_ptr<Route>
1874 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1876 boost::shared_ptr<Route> ret;
1878 if (node.name() != "Route") {
1882 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1884 DataType type = DataType::AUDIO;
1885 node.get_property("default-type", type);
1887 assert (type != DataType::NIL);
1891 boost::shared_ptr<Track> track;
1893 if (type == DataType::AUDIO) {
1894 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1896 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1899 if (track->init()) {
1903 if (track->set_state (node, version)) {
1907 BOOST_MARK_TRACK (track);
1911 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1912 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1914 if (r->init () == 0 && r->set_state (node, version) == 0) {
1915 BOOST_MARK_ROUTE (r);
1923 boost::shared_ptr<Route>
1924 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1926 boost::shared_ptr<Route> ret;
1928 if (node.name() != "Route") {
1932 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1934 ds_prop = node.property (X_("diskstream"));
1937 DataType type = DataType::AUDIO;
1938 node.get_property("default-type", type);
1940 assert (type != DataType::NIL);
1944 /* see comment in current ::set_state() regarding diskstream
1945 * state and DiskReader/DiskWRiter.
1948 error << _("Could not find diskstream for route") << endmsg;
1949 return boost::shared_ptr<Route> ();
1951 boost::shared_ptr<Track> track;
1953 if (type == DataType::AUDIO) {
1954 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1956 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1959 if (track->init()) {
1963 if (track->set_state (node, version)) {
1967 BOOST_MARK_TRACK (track);
1971 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1972 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1974 if (r->init () == 0 && r->set_state (node, version) == 0) {
1975 BOOST_MARK_ROUTE (r);
1984 Session::load_regions (const XMLNode& node)
1987 XMLNodeConstIterator niter;
1988 boost::shared_ptr<Region> region;
1990 nlist = node.children();
1994 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1995 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1996 error << _("Session: cannot create Region from XML description.");
1997 XMLProperty const * name = (**niter).property("name");
2000 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
2011 Session::load_compounds (const XMLNode& node)
2013 XMLNodeList calist = node.children();
2014 XMLNodeConstIterator caiter;
2015 XMLProperty const * caprop;
2017 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
2018 XMLNode* ca = *caiter;
2022 if ((caprop = ca->property (X_("original"))) == 0) {
2025 orig_id = caprop->value();
2027 if ((caprop = ca->property (X_("copy"))) == 0) {
2030 copy_id = caprop->value();
2032 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2033 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2035 if (!orig || !copy) {
2036 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2042 RegionFactory::add_compound_association (orig, copy);
2049 Session::load_nested_sources (const XMLNode& node)
2052 XMLNodeConstIterator niter;
2054 nlist = node.children();
2056 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2057 if ((*niter)->name() == "Source") {
2059 /* it may already exist, so don't recreate it unnecessarily
2062 XMLProperty const * prop = (*niter)->property (X_("id"));
2064 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2068 ID source_id (prop->value());
2070 if (!source_by_id (source_id)) {
2073 SourceFactory::create (*this, **niter, true);
2075 catch (failed_constructor& err) {
2076 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2083 boost::shared_ptr<Region>
2084 Session::XMLRegionFactory (const XMLNode& node, bool full)
2086 XMLProperty const * type = node.property("type");
2090 const XMLNodeList& nlist = node.children();
2092 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2093 XMLNode *child = (*niter);
2094 if (child->name() == "NestedSource") {
2095 load_nested_sources (*child);
2099 if (!type || type->value() == "audio") {
2100 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2101 } else if (type->value() == "midi") {
2102 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2105 } catch (failed_constructor& err) {
2106 return boost::shared_ptr<Region> ();
2109 return boost::shared_ptr<Region> ();
2112 boost::shared_ptr<AudioRegion>
2113 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2115 XMLProperty const * prop;
2116 boost::shared_ptr<Source> source;
2117 boost::shared_ptr<AudioSource> as;
2119 SourceList master_sources;
2120 uint32_t nchans = 1;
2123 if (node.name() != X_("Region")) {
2124 return boost::shared_ptr<AudioRegion>();
2127 node.get_property (X_("channels"), nchans);
2129 if ((prop = node.property ("name")) == 0) {
2130 cerr << "no name for this region\n";
2134 if ((prop = node.property (X_("source-0"))) == 0) {
2135 if ((prop = node.property ("source")) == 0) {
2136 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2137 return boost::shared_ptr<AudioRegion>();
2141 PBD::ID s_id (prop->value());
2143 if ((source = source_by_id (s_id)) == 0) {
2144 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2145 return boost::shared_ptr<AudioRegion>();
2148 as = boost::dynamic_pointer_cast<AudioSource>(source);
2150 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2151 return boost::shared_ptr<AudioRegion>();
2154 sources.push_back (as);
2156 /* pickup other channels */
2158 for (uint32_t n=1; n < nchans; ++n) {
2159 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2160 if ((prop = node.property (buf)) != 0) {
2162 PBD::ID id2 (prop->value());
2164 if ((source = source_by_id (id2)) == 0) {
2165 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2166 return boost::shared_ptr<AudioRegion>();
2169 as = boost::dynamic_pointer_cast<AudioSource>(source);
2171 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2172 return boost::shared_ptr<AudioRegion>();
2174 sources.push_back (as);
2178 for (uint32_t n = 0; n < nchans; ++n) {
2179 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2180 if ((prop = node.property (buf)) != 0) {
2182 PBD::ID id2 (prop->value());
2184 if ((source = source_by_id (id2)) == 0) {
2185 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2186 return boost::shared_ptr<AudioRegion>();
2189 as = boost::dynamic_pointer_cast<AudioSource>(source);
2191 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2192 return boost::shared_ptr<AudioRegion>();
2194 master_sources.push_back (as);
2199 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2201 /* a final detail: this is the one and only place that we know how long missing files are */
2203 if (region->whole_file()) {
2204 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2205 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2207 sfp->set_length (region->length());
2212 if (!master_sources.empty()) {
2213 if (master_sources.size() != nchans) {
2214 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2216 region->set_master_sources (master_sources);
2224 catch (failed_constructor& err) {
2225 return boost::shared_ptr<AudioRegion>();
2229 boost::shared_ptr<MidiRegion>
2230 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2232 XMLProperty const * prop;
2233 boost::shared_ptr<Source> source;
2234 boost::shared_ptr<MidiSource> ms;
2237 if (node.name() != X_("Region")) {
2238 return boost::shared_ptr<MidiRegion>();
2241 if ((prop = node.property ("name")) == 0) {
2242 cerr << "no name for this region\n";
2246 if ((prop = node.property (X_("source-0"))) == 0) {
2247 if ((prop = node.property ("source")) == 0) {
2248 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2249 return boost::shared_ptr<MidiRegion>();
2253 PBD::ID s_id (prop->value());
2255 if ((source = source_by_id (s_id)) == 0) {
2256 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2257 return boost::shared_ptr<MidiRegion>();
2260 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2262 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2263 return boost::shared_ptr<MidiRegion>();
2266 sources.push_back (ms);
2269 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2270 /* a final detail: this is the one and only place that we know how long missing files are */
2272 if (region->whole_file()) {
2273 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2274 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2276 sfp->set_length (region->length());
2284 catch (failed_constructor& err) {
2285 return boost::shared_ptr<MidiRegion>();
2290 Session::get_sources_as_xml ()
2293 XMLNode* node = new XMLNode (X_("Sources"));
2294 Glib::Threads::Mutex::Lock lm (source_lock);
2296 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2297 node->add_child_nocopy (i->second->get_state());
2304 Session::reset_write_sources (bool mark_write_complete, bool force)
2306 boost::shared_ptr<RouteList> rl = routes.reader();
2307 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2308 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2310 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2311 tr->reset_write_sources(mark_write_complete, force);
2312 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2318 Session::load_sources (const XMLNode& node)
2321 XMLNodeConstIterator niter;
2322 /* don't need this but it stops some
2323 * versions of gcc complaining about
2324 * discarded return values.
2326 boost::shared_ptr<Source> source;
2328 nlist = node.children();
2331 std::map<std::string, std::string> relocation;
2333 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2334 #ifdef PLATFORM_WINDOWS
2338 XMLNode srcnode (**niter);
2339 bool try_replace_abspath = true;
2343 #ifdef PLATFORM_WINDOWS
2344 // do not show "insert media" popups (files embedded from removable media).
2345 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2347 if ((source = XMLSourceFactory (srcnode)) == 0) {
2348 error << _("Session: cannot create Source from XML description.") << endmsg;
2350 #ifdef PLATFORM_WINDOWS
2351 SetErrorMode(old_mode);
2354 } catch (MissingSource& err) {
2355 #ifdef PLATFORM_WINDOWS
2356 SetErrorMode(old_mode);
2359 /* try previous abs path replacements first */
2360 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2361 std::string dir = Glib::path_get_dirname (err.path);
2362 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2363 if (rl != relocation.end ()) {
2364 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2365 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2366 srcnode.set_property ("origin", newpath);
2367 try_replace_abspath = false;
2374 _missing_file_replacement = "";
2376 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2377 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2378 PROGRAM_NAME) << endmsg;
2382 if (!no_questions_about_missing_files) {
2383 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2388 switch (user_choice) {
2390 /* user added a new search location
2391 * or selected a new absolute path,
2393 if (Glib::path_is_absolute (err.path)) {
2394 if (!_missing_file_replacement.empty ()) {
2395 /* replace origin, in XML */
2396 std::string newpath = Glib::build_filename (
2397 _missing_file_replacement, Glib::path_get_basename (err.path));
2398 srcnode.set_property ("origin", newpath);
2399 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2400 _missing_file_replacement = "";
2407 /* user asked to quit the entire session load */
2411 no_questions_about_missing_files = true;
2415 no_questions_about_missing_files = true;
2422 case DataType::AUDIO:
2423 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2426 case DataType::MIDI:
2427 /* The MIDI file is actually missing so
2428 * just create a new one in the same
2429 * location. Do not announce its
2433 if (!Glib::path_is_absolute (err.path)) {
2434 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2436 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2441 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2442 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2443 /* reset ID to match the missing one */
2444 source->set_id (**niter);
2445 /* Now we can announce it */
2446 SourceFactory::SourceCreated (source);
2457 boost::shared_ptr<Source>
2458 Session::XMLSourceFactory (const XMLNode& node)
2460 if (node.name() != "Source") {
2461 return boost::shared_ptr<Source>();
2465 /* note: do peak building in another thread when loading session state */
2466 return SourceFactory::create (*this, node, true);
2469 catch (failed_constructor& err) {
2470 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2471 return boost::shared_ptr<Source>();
2476 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2478 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2482 bool absolute_path = Glib::path_is_absolute (template_name);
2484 /* directory to put the template in */
2485 std::string template_dir_path;
2487 if (!absolute_path) {
2488 std::string user_template_dir(user_template_directory());
2490 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2491 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2492 user_template_dir, g_strerror (errno)) << endmsg;
2496 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2498 template_dir_path = template_name;
2501 if (!ARDOUR::Profile->get_trx()) {
2502 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2503 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2504 template_dir_path) << endmsg;
2508 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2509 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2510 template_dir_path, g_strerror (errno)) << endmsg;
2516 std::string template_file_path;
2518 if (ARDOUR::Profile->get_trx()) {
2519 template_file_path = template_name;
2521 if (absolute_path) {
2522 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2524 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2528 SessionSaveUnderway (); /* EMIT SIGNAL */
2533 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2534 root = &get_template ();
2537 root->remove_nodes_and_delete (X_("description"));
2539 if (!description.empty()) {
2540 XMLNode* desc = new XMLNode (X_("description"));
2541 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2542 desc->add_child_nocopy (*desc_cont);
2544 root->add_child_nocopy (*desc);
2547 tree.set_root (root);
2549 if (!tree.write (template_file_path)) {
2550 error << _("template not saved") << endmsg;
2554 store_recent_templates (template_file_path);
2560 Session::refresh_disk_space ()
2562 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2564 Glib::Threads::Mutex::Lock lm (space_lock);
2566 /* get freespace on every FS that is part of the session path */
2568 _total_free_4k_blocks = 0;
2569 _total_free_4k_blocks_uncertain = false;
2571 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2572 #if defined(__NetBSD__)
2573 struct statvfs statfsbuf;
2575 statvfs (i->path.c_str(), &statfsbuf);
2577 struct statfs statfsbuf;
2579 statfs (i->path.c_str(), &statfsbuf);
2581 double const scale = statfsbuf.f_bsize / 4096.0;
2583 /* See if this filesystem is read-only */
2584 struct statvfs statvfsbuf;
2585 statvfs (i->path.c_str(), &statvfsbuf);
2587 /* f_bavail can be 0 if it is undefined for whatever
2588 filesystem we are looking at; Samba shares mounted
2589 via GVFS are an example of this.
2591 if (statfsbuf.f_bavail == 0) {
2592 /* block count unknown */
2594 i->blocks_unknown = true;
2595 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2596 /* read-only filesystem */
2598 i->blocks_unknown = false;
2600 /* read/write filesystem with known space */
2601 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2602 i->blocks_unknown = false;
2605 _total_free_4k_blocks += i->blocks;
2606 if (i->blocks_unknown) {
2607 _total_free_4k_blocks_uncertain = true;
2610 #elif defined PLATFORM_WINDOWS
2611 vector<string> scanned_volumes;
2612 vector<string>::iterator j;
2613 vector<space_and_path>::iterator i;
2614 DWORD nSectorsPerCluster, nBytesPerSector,
2615 nFreeClusters, nTotalClusters;
2619 _total_free_4k_blocks = 0;
2621 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2622 strncpy (disk_drive, (*i).path.c_str(), 3);
2626 volume_found = false;
2627 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2629 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2630 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2631 i->blocks = (uint32_t)(nFreeBytes / 4096);
2633 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2634 if (0 == j->compare(disk_drive)) {
2635 volume_found = true;
2640 if (!volume_found) {
2641 scanned_volumes.push_back(disk_drive);
2642 _total_free_4k_blocks += i->blocks;
2647 if (0 == _total_free_4k_blocks) {
2648 strncpy (disk_drive, path().c_str(), 3);
2651 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2653 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2654 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2655 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2662 Session::get_best_session_directory_for_new_audio ()
2664 vector<space_and_path>::iterator i;
2665 string result = _session_dir->root_path();
2667 /* handle common case without system calls */
2669 if (session_dirs.size() == 1) {
2673 /* OK, here's the algorithm we're following here:
2675 We want to select which directory to use for
2676 the next file source to be created. Ideally,
2677 we'd like to use a round-robin process so as to
2678 get maximum performance benefits from splitting
2679 the files across multiple disks.
2681 However, in situations without much diskspace, an
2682 RR approach may end up filling up a filesystem
2683 with new files while others still have space.
2684 Its therefore important to pay some attention to
2685 the freespace in the filesystem holding each
2686 directory as well. However, if we did that by
2687 itself, we'd keep creating new files in the file
2688 system with the most space until it was as full
2689 as all others, thus negating any performance
2690 benefits of this RAID-1 like approach.
2692 So, we use a user-configurable space threshold. If
2693 there are at least 2 filesystems with more than this
2694 much space available, we use RR selection between them.
2695 If not, then we pick the filesystem with the most space.
2697 This gets a good balance between the two
2701 refresh_disk_space ();
2703 int free_enough = 0;
2705 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2706 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2711 if (free_enough >= 2) {
2712 /* use RR selection process, ensuring that the one
2716 i = last_rr_session_dir;
2719 if (++i == session_dirs.end()) {
2720 i = session_dirs.begin();
2723 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2724 SessionDirectory sdir(i->path);
2725 if (sdir.create ()) {
2727 last_rr_session_dir = i;
2732 } while (i != last_rr_session_dir);
2736 /* pick FS with the most freespace (and that
2737 seems to actually work ...)
2740 vector<space_and_path> sorted;
2741 space_and_path_ascending_cmp cmp;
2743 sorted = session_dirs;
2744 sort (sorted.begin(), sorted.end(), cmp);
2746 for (i = sorted.begin(); i != sorted.end(); ++i) {
2747 SessionDirectory sdir(i->path);
2748 if (sdir.create ()) {
2750 last_rr_session_dir = i;
2760 Session::automation_dir () const
2762 return Glib::build_filename (_path, automation_dir_name);
2766 Session::analysis_dir () const
2768 return Glib::build_filename (_path, analysis_dir_name);
2772 Session::plugins_dir () const
2774 return Glib::build_filename (_path, plugins_dir_name);
2778 Session::externals_dir () const
2780 return Glib::build_filename (_path, externals_dir_name);
2784 Session::load_bundles (XMLNode const & node)
2786 XMLNodeList nlist = node.children();
2787 XMLNodeConstIterator niter;
2791 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2792 if ((*niter)->name() == "InputBundle") {
2793 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2794 } else if ((*niter)->name() == "OutputBundle") {
2795 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2797 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2806 Session::load_route_groups (const XMLNode& node, int version)
2808 XMLNodeList nlist = node.children();
2809 XMLNodeConstIterator niter;
2813 if (version >= 3000) {
2815 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2816 if ((*niter)->name() == "RouteGroup") {
2817 RouteGroup* rg = new RouteGroup (*this, "");
2818 add_route_group (rg);
2819 rg->set_state (**niter, version);
2823 } else if (version < 3000) {
2825 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2826 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2827 RouteGroup* rg = new RouteGroup (*this, "");
2828 add_route_group (rg);
2829 rg->set_state (**niter, version);
2838 state_file_filter (const string &str, void* /*arg*/)
2840 return (str.length() > strlen(statefile_suffix) &&
2841 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2845 remove_end(string state)
2847 string statename(state);
2849 string::size_type start,end;
2850 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2851 statename = statename.substr (start+1);
2854 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2855 end = statename.length();
2858 return string(statename.substr (0, end));
2862 Session::possible_states (string path)
2864 vector<string> states;
2865 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2867 transform(states.begin(), states.end(), states.begin(), remove_end);
2869 sort (states.begin(), states.end());
2875 Session::possible_states () const
2877 return possible_states(_path);
2881 Session::new_route_group (const std::string& name)
2883 RouteGroup* rg = NULL;
2885 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2886 if ((*i)->name () == name) {
2893 rg = new RouteGroup (*this, name);
2894 add_route_group (rg);
2900 Session::add_route_group (RouteGroup* g)
2902 _route_groups.push_back (g);
2903 route_group_added (g); /* EMIT SIGNAL */
2905 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2906 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2907 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2913 Session::remove_route_group (RouteGroup& rg)
2915 list<RouteGroup*>::iterator i;
2917 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2918 _route_groups.erase (i);
2921 route_group_removed (); /* EMIT SIGNAL */
2925 /** Set a new order for our route groups, without adding or removing any.
2926 * @param groups Route group list in the new order.
2929 Session::reorder_route_groups (list<RouteGroup*> groups)
2931 _route_groups = groups;
2933 route_groups_reordered (); /* EMIT SIGNAL */
2939 Session::route_group_by_name (string name)
2941 list<RouteGroup *>::iterator i;
2943 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2944 if ((*i)->name() == name) {
2952 Session::all_route_group() const
2954 return *_all_route_group;
2958 Session::add_commands (vector<Command*> const & cmds)
2960 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2966 Session::add_command (Command* const cmd)
2968 assert (_current_trans);
2969 DEBUG_UNDO_HISTORY (
2970 string_compose ("Current Undo Transaction %1, adding command: %2",
2971 _current_trans->name (),
2973 _current_trans->add_command (cmd);
2976 PBD::StatefulDiffCommand*
2977 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2979 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2985 Session::begin_reversible_command (const string& name)
2987 begin_reversible_command (g_quark_from_string (name.c_str ()));
2990 /** Begin a reversible command using a GQuark to identify it.
2991 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2992 * but there must be as many begin...()s as there are commit...()s.
2995 Session::begin_reversible_command (GQuark q)
2997 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2998 to hold all the commands that are committed. This keeps the order of
2999 commands correct in the history.
3002 if (_current_trans == 0) {
3003 DEBUG_UNDO_HISTORY (string_compose (
3004 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
3006 /* start a new transaction */
3007 assert (_current_trans_quarks.empty ());
3008 _current_trans = new UndoTransaction();
3009 _current_trans->set_name (g_quark_to_string (q));
3011 DEBUG_UNDO_HISTORY (
3012 string_compose ("Begin Reversible Command, current transaction: %1",
3013 _current_trans->name ()));
3016 _current_trans_quarks.push_front (q);
3020 Session::abort_reversible_command ()
3022 if (_current_trans != 0) {
3023 DEBUG_UNDO_HISTORY (
3024 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
3025 _current_trans->clear();
3026 delete _current_trans;
3028 _current_trans_quarks.clear();
3033 Session::commit_reversible_command (Command *cmd)
3035 assert (_current_trans);
3036 assert (!_current_trans_quarks.empty ());
3041 DEBUG_UNDO_HISTORY (
3042 string_compose ("Current Undo Transaction %1, adding command: %2",
3043 _current_trans->name (),
3045 _current_trans->add_command (cmd);
3048 DEBUG_UNDO_HISTORY (
3049 string_compose ("Commit Reversible Command, current transaction: %1",
3050 _current_trans->name ()));
3052 _current_trans_quarks.pop_front ();
3054 if (!_current_trans_quarks.empty ()) {
3055 DEBUG_UNDO_HISTORY (
3056 string_compose ("Commit Reversible Command, transaction is not "
3057 "top-level, current transaction: %1",
3058 _current_trans->name ()));
3059 /* the transaction we're committing is not the top-level one */
3063 if (_current_trans->empty()) {
3064 /* no commands were added to the transaction, so just get rid of it */
3065 DEBUG_UNDO_HISTORY (
3066 string_compose ("Commit Reversible Command, No commands were "
3067 "added to current transaction: %1",
3068 _current_trans->name ()));
3069 delete _current_trans;
3074 gettimeofday (&now, 0);
3075 _current_trans->set_timestamp (now);
3077 _history.add (_current_trans);
3082 accept_all_audio_files (const string& path, void* /*arg*/)
3084 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3088 if (!AudioFileSource::safe_audio_file_extension (path)) {
3096 accept_all_midi_files (const string& path, void* /*arg*/)
3098 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3102 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3103 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3104 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3108 accept_all_state_files (const string& path, void* /*arg*/)
3110 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3114 std::string const statefile_ext (statefile_suffix);
3115 if (path.length() >= statefile_ext.length()) {
3116 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3123 Session::find_all_sources (string path, set<string>& result)
3128 if (!tree.read (path)) {
3132 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3137 XMLNodeConstIterator niter;
3139 nlist = node->children();
3143 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3145 XMLProperty const * prop;
3147 if ((prop = (*niter)->property (X_("type"))) == 0) {
3151 DataType type (prop->value());
3153 if ((prop = (*niter)->property (X_("name"))) == 0) {
3157 if (Glib::path_is_absolute (prop->value())) {
3158 /* external file, ignore */
3166 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3167 result.insert (found_path);
3175 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3177 vector<string> state_files;
3179 string this_snapshot_path;
3185 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3186 ripped = ripped.substr (0, ripped.length() - 1);
3189 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3191 if (state_files.empty()) {
3196 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3197 this_snapshot_path += statefile_suffix;
3199 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3201 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3203 if (exclude_this_snapshot && *i == this_snapshot_path) {
3204 cerr << "\texcluded\n";
3209 if (find_all_sources (*i, result) < 0) {
3217 struct RegionCounter {
3218 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3219 AudioSourceList::iterator iter;
3220 boost::shared_ptr<Region> region;
3223 RegionCounter() : count (0) {}
3227 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3229 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3230 return r.get_value_or (1);
3234 Session::cleanup_regions ()
3236 bool removed = false;
3237 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3239 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3241 uint32_t used = playlists->region_use_count (i->second);
3243 if (used == 0 && !i->second->automatic ()) {
3244 boost::weak_ptr<Region> w = i->second;
3247 RegionFactory::map_remove (w);
3254 // re-check to remove parent references of compound regions
3255 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3256 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3260 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3261 if (0 == playlists->region_use_count (i->second)) {
3262 boost::weak_ptr<Region> w = i->second;
3264 RegionFactory::map_remove (w);
3271 /* dump the history list */
3278 Session::can_cleanup_peakfiles () const
3280 if (deletion_in_progress()) {
3283 if (!_writable || (_state_of_the_state & CannotSave)) {
3284 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3287 if (record_status() == Recording) {
3288 error << _("Cannot cleanup peak-files while recording") << endmsg;
3295 Session::cleanup_peakfiles ()
3297 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3302 assert (can_cleanup_peakfiles ());
3303 assert (!peaks_cleanup_in_progres());
3305 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3307 int timeout = 5000; // 5 seconds
3308 while (!SourceFactory::files_with_peaks.empty()) {
3309 Glib::usleep (1000);
3310 if (--timeout < 0) {
3311 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3312 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3317 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3318 boost::shared_ptr<AudioSource> as;
3319 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3320 as->close_peakfile();
3324 PBD::clear_directory (session_directory().peak_path());
3326 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3328 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3329 boost::shared_ptr<AudioSource> as;
3330 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3331 SourceFactory::setup_peakfile(as, true);
3338 Session::cleanup_sources (CleanupReport& rep)
3340 // FIXME: needs adaptation to midi
3342 vector<boost::shared_ptr<Source> > dead_sources;
3345 vector<string> candidates;
3346 vector<string> unused;
3347 set<string> sources_used_by_all_snapshots;
3354 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3356 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3358 /* this is mostly for windows which doesn't allow file
3359 * renaming if the file is in use. But we don't special
3360 * case it because we need to know if this causes
3361 * problems, and the easiest way to notice that is to
3362 * keep it in place for all platforms.
3365 request_stop (false);
3367 _butler->wait_until_finished ();
3369 /* consider deleting all unused playlists */
3371 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3376 /* sync the "all regions" property of each playlist with its current state */
3378 playlists->sync_all_regions_with_regions ();
3380 /* find all un-used sources */
3385 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3387 SourceMap::iterator tmp;
3392 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3396 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3397 dead_sources.push_back (i->second);
3398 i->second->drop_references ();
3404 /* build a list of all the possible audio directories for the session */
3406 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3407 SessionDirectory sdir ((*i).path);
3408 asp += sdir.sound_path();
3410 audio_path += asp.to_string();
3413 /* build a list of all the possible midi directories for the session */
3415 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3416 SessionDirectory sdir ((*i).path);
3417 msp += sdir.midi_path();
3419 midi_path += msp.to_string();
3421 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3422 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3424 /* add sources from all other snapshots as "used", but don't use this
3425 snapshot because the state file on disk still references sources we
3426 may have already dropped.
3429 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3431 /* Although the region factory has a list of all regions ever created
3432 * for this session, we're only interested in regions actually in
3433 * playlists right now. So merge all playlist regions lists together.
3435 * This will include the playlists used within compound regions.
3438 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3440 /* add our current source list
3443 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3444 boost::shared_ptr<FileSource> fs;
3445 SourceMap::iterator tmp = i;
3448 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3454 /* this is mostly for windows which doesn't allow file
3455 * renaming if the file is in use. But we do not special
3456 * case it because we need to know if this causes
3457 * problems, and the easiest way to notice that is to
3458 * keep it in place for all platforms.
3463 if (!fs->is_stub()) {
3465 /* Note that we're checking a list of all
3466 * sources across all snapshots with the list
3467 * of sources used by this snapshot.
3470 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3471 /* this source is in use by this snapshot */
3472 sources_used_by_all_snapshots.insert (fs->path());
3473 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3475 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3476 /* this source is NOT in use by this snapshot */
3478 /* remove all related regions from RegionFactory master list */
3480 RegionFactory::remove_regions_using_source (i->second);
3482 /* remove from our current source list
3483 * also. We may not remove it from
3484 * disk, because it may be used by
3485 * other snapshots, but it isn't used inside this
3486 * snapshot anymore, so we don't need a
3497 /* now check each candidate source to see if it exists in the list of
3498 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3501 cerr << "Candidates: " << candidates.size() << endl;
3502 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3504 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3509 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3511 tmppath1 = canonical_path (spath);
3512 tmppath2 = canonical_path ((*i));
3514 cerr << "\t => " << tmppath2 << endl;
3516 if (tmppath1 == tmppath2) {
3523 unused.push_back (spath);
3527 cerr << "Actually unused: " << unused.size() << endl;
3529 if (unused.empty()) {
3535 /* now try to move all unused files into the "dead" directory(ies) */
3537 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3542 /* don't move the file across filesystems, just
3543 * stick it in the `dead_dir_name' directory
3544 * on whichever filesystem it was already on.
3547 if ((*x).find ("/sounds/") != string::npos) {
3549 /* old school, go up 1 level */
3551 newpath = Glib::path_get_dirname (*x); // "sounds"
3552 newpath = Glib::path_get_dirname (newpath); // "session-name"
3556 /* new school, go up 4 levels */
3558 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3559 newpath = Glib::path_get_dirname (newpath); // "session-name"
3560 newpath = Glib::path_get_dirname (newpath); // "interchange"
3561 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3564 newpath = Glib::build_filename (newpath, dead_dir_name);
3566 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3567 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3571 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3573 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3575 /* the new path already exists, try versioning */
3577 char buf[PATH_MAX+1];
3581 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3584 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3585 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3589 if (version == 999) {
3590 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3594 newpath = newpath_v;
3599 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3600 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3601 newpath, g_strerror (errno)) << endmsg;
3605 /* see if there an easy to find peakfile for this file, and remove it. */
3607 string base = Glib::path_get_basename (*x);
3608 base += "%A"; /* this is what we add for the channel suffix of all native files,
3609 * or for the first channel of embedded files. it will miss
3610 * some peakfiles for other channels
3612 string peakpath = construct_peak_filepath (base);
3614 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3615 if (::g_unlink (peakpath.c_str ()) != 0) {
3616 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3617 g_strerror (errno)) << endmsg;
3618 /* try to back out */
3619 ::g_rename (newpath.c_str (), _path.c_str ());
3624 rep.paths.push_back (*x);
3625 rep.space += statbuf.st_size;
3628 /* dump the history list */
3632 /* save state so we don't end up a session file
3633 * referring to non-existent sources.
3640 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3646 Session::cleanup_trash_sources (CleanupReport& rep)
3648 // FIXME: needs adaptation for MIDI
3650 vector<space_and_path>::iterator i;
3656 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3658 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3660 clear_directory (dead_dir, &rep.space, &rep.paths);
3667 Session::set_dirty ()
3669 /* return early if there's nothing to do */
3674 /* never mark session dirty during loading */
3675 if (_state_of_the_state & (Loading | Deletion)) {
3679 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3680 DirtyChanged(); /* EMIT SIGNAL */
3684 Session::set_clean ()
3686 bool was_dirty = dirty();
3688 _state_of_the_state = Clean;
3691 DirtyChanged(); /* EMIT SIGNAL */
3696 Session::set_deletion_in_progress ()
3698 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3702 Session::clear_deletion_in_progress ()
3704 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3708 Session::add_controllable (boost::shared_ptr<Controllable> c)
3710 /* this adds a controllable to the list managed by the Session.
3711 this is a subset of those managed by the Controllable class
3712 itself, and represents the only ones whose state will be saved
3713 as part of the session.
3716 Glib::Threads::Mutex::Lock lm (controllables_lock);
3717 controllables.insert (c);
3720 struct null_deleter { void operator()(void const *) const {} };
3723 Session::remove_controllable (Controllable* c)
3725 if (_state_of_the_state & Deletion) {
3729 Glib::Threads::Mutex::Lock lm (controllables_lock);
3731 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3733 if (x != controllables.end()) {
3734 controllables.erase (x);
3738 boost::shared_ptr<Controllable>
3739 Session::controllable_by_id (const PBD::ID& id)
3741 Glib::Threads::Mutex::Lock lm (controllables_lock);
3743 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3744 if ((*i)->id() == id) {
3749 return boost::shared_ptr<Controllable>();
3752 boost::shared_ptr<AutomationControl>
3753 Session::automation_control_by_id (const PBD::ID& id)
3755 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3759 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3762 Stateful::add_instant_xml (node, _path);
3765 if (write_to_config) {
3766 Config->add_instant_xml (node);
3771 Session::instant_xml (const string& node_name)
3773 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3774 if (get_disable_all_loaded_plugins ()) {
3778 return Stateful::instant_xml (node_name, _path);
3782 Session::save_history (string snapshot_name)
3790 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3791 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3795 if (snapshot_name.empty()) {
3796 snapshot_name = _current_snapshot_name;
3799 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3800 const string backup_filename = history_filename + backup_suffix;
3801 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3802 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3804 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3805 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3806 error << _("could not backup old history file, current history not saved") << endmsg;
3811 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3813 if (!tree.write (xml_path))
3815 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3817 if (g_remove (xml_path.c_str()) != 0) {
3818 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3819 xml_path, g_strerror (errno)) << endmsg;
3821 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3822 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3823 backup_path, g_strerror (errno)) << endmsg;
3833 Session::restore_history (string snapshot_name)
3837 if (snapshot_name.empty()) {
3838 snapshot_name = _current_snapshot_name;
3841 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3842 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3844 info << "Loading history from " << xml_path << endmsg;
3846 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3847 info << string_compose (_("%1: no history file \"%2\" for this session."),
3848 _name, xml_path) << endmsg;
3852 if (!tree.read (xml_path)) {
3853 error << string_compose (_("Could not understand session history file \"%1\""),
3854 xml_path) << endmsg;
3861 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3869 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3870 !t->get_property ("tv-usec", tv_usec)) {
3874 UndoTransaction* ut = new UndoTransaction ();
3875 ut->set_name (name);
3879 tv.tv_usec = tv_usec;
3880 ut->set_timestamp(tv);
3882 for (XMLNodeConstIterator child_it = t->children().begin();
3883 child_it != t->children().end(); child_it++)
3885 XMLNode *n = *child_it;
3888 if (n->name() == "MementoCommand" ||
3889 n->name() == "MementoUndoCommand" ||
3890 n->name() == "MementoRedoCommand") {
3892 if ((c = memento_command_factory(n))) {
3896 } else if (n->name() == "NoteDiffCommand") {
3897 PBD::ID id (n->property("midi-source")->value());
3898 boost::shared_ptr<MidiSource> midi_source =
3899 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3901 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3903 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3906 } else if (n->name() == "SysExDiffCommand") {
3908 PBD::ID id (n->property("midi-source")->value());
3909 boost::shared_ptr<MidiSource> midi_source =
3910 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3912 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3914 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3917 } else if (n->name() == "PatchChangeDiffCommand") {
3919 PBD::ID id (n->property("midi-source")->value());
3920 boost::shared_ptr<MidiSource> midi_source =
3921 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3923 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3925 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3928 } else if (n->name() == "StatefulDiffCommand") {
3929 if ((c = stateful_diff_command_factory (n))) {
3930 ut->add_command (c);
3933 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3944 Session::config_changed (std::string p, bool ours)
3950 if (p == "auto-loop") {
3952 } else if (p == "session-monitoring") {
3954 } else if (p == "auto-input") {
3956 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3957 /* auto-input only makes a difference if we're rolling */
3958 set_track_monitor_input_status (!config.get_auto_input());
3961 } else if (p == "punch-in") {
3965 if ((location = _locations->auto_punch_location()) != 0) {
3967 if (config.get_punch_in ()) {
3968 auto_punch_start_changed (location);
3970 clear_events (SessionEvent::PunchIn);
3974 } else if (p == "punch-out") {
3978 if ((location = _locations->auto_punch_location()) != 0) {
3980 if (config.get_punch_out()) {
3981 auto_punch_end_changed (location);
3983 clear_events (SessionEvent::PunchOut);
3987 } else if (p == "edit-mode") {
3989 Glib::Threads::Mutex::Lock lm (playlists->lock);
3991 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3992 (*i)->set_edit_mode (Config->get_edit_mode ());
3995 } else if (p == "use-video-sync") {
3997 waiting_for_sync_offset = config.get_use_video_sync();
3999 } else if (p == "mmc-control") {
4001 //poke_midi_thread ();
4003 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4005 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4007 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4009 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4011 } else if (p == "midi-control") {
4013 //poke_midi_thread ();
4015 } else if (p == "raid-path") {
4017 setup_raid_path (config.get_raid_path());
4019 } else if (p == "timecode-format") {
4023 } else if (p == "video-pullup") {
4027 } else if (p == "seamless-loop") {
4029 if (play_loop && transport_rolling()) {
4030 // to reset diskstreams etc
4031 request_play_loop (true);
4034 } else if (p == "rf-speed") {
4036 cumulative_rf_motion = 0;
4039 } else if (p == "click-sound") {
4041 setup_click_sounds (1);
4043 } else if (p == "click-emphasis-sound") {
4045 setup_click_sounds (-1);
4047 } else if (p == "clicking") {
4049 if (Config->get_clicking()) {
4050 if (_click_io && click_data) { // don't require emphasis data
4057 } else if (p == "click-record-only") {
4059 _click_rec_only = Config->get_click_record_only();
4061 } else if (p == "click-gain") {
4064 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4067 } else if (p == "send-mtc") {
4069 if (Config->get_send_mtc ()) {
4070 /* mark us ready to send */
4071 next_quarter_frame_to_send = 0;
4074 } else if (p == "send-mmc") {
4076 _mmc->enable_send (Config->get_send_mmc ());
4077 if (Config->get_send_mmc ()) {
4078 /* re-initialize MMC */
4079 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4080 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4083 } else if (p == "jack-time-master") {
4085 engine().reset_timebase ();
4087 } else if (p == "native-file-header-format") {
4089 if (!first_file_header_format_reset) {
4090 reset_native_file_format ();
4093 first_file_header_format_reset = false;
4095 } else if (p == "native-file-data-format") {
4097 if (!first_file_data_format_reset) {
4098 reset_native_file_format ();
4101 first_file_data_format_reset = false;
4103 } else if (p == "external-sync") {
4104 std::cerr << "param change, rss to " << TransportMasterManager::instance().current() << std::endl;
4105 request_sync_source (TransportMasterManager::instance().current());
4106 } else if (p == "denormal-model") {
4108 } else if (p == "history-depth") {
4109 set_history_depth (Config->get_history_depth());
4110 } else if (p == "remote-model") {
4111 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4114 } else if (p == "initial-program-change") {
4116 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4119 buf[0] = MIDI::program; // channel zero by default
4120 buf[1] = (Config->get_initial_program_change() & 0x7f);
4122 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4124 } else if (p == "solo-mute-override") {
4125 // catch_up_on_solo_mute_override ();
4126 } else if (p == "listen-position" || p == "pfl-position") {
4127 listen_position_changed ();
4128 } else if (p == "solo-control-is-listen-control") {
4129 solo_control_mode_changed ();
4130 } else if (p == "solo-mute-gain") {
4131 _solo_cut_control->Changed (true, Controllable::NoGroup);
4132 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4133 last_timecode_valid = false;
4134 } else if (p == "playback-buffer-seconds") {
4135 AudioSource::allocate_working_buffers (sample_rate());
4136 } else if (p == "ltc-sink-port") {
4137 reconnect_ltc_output ();
4138 } else if (p == "timecode-generator-offset") {
4139 ltc_tx_parse_offset();
4140 } else if (p == "auto-return-target-list") {
4141 follow_playhead_priority ();
4142 } else if (p == "use-monitor-bus") {
4143 bool yn = Config->get_use_monitor_bus();
4144 if (yn && !_monitor_out) {
4145 add_monitor_section ();
4146 } else if (!yn && _monitor_out) {
4147 remove_monitor_section ();
4155 Session::set_history_depth (uint32_t d)
4157 _history.set_depth (d);
4160 /** Connect things to the MMC object */
4162 Session::setup_midi_machine_control ()
4164 _mmc = new MIDI::MachineControl;
4166 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4167 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4169 if (!async_out || !async_out) {
4173 /* XXXX argh, passing raw pointers back into libmidi++ */
4175 MIDI::Port* mmc_in = async_in.get();
4176 MIDI::Port* mmc_out = async_out.get();
4178 _mmc->set_ports (mmc_in, mmc_out);
4180 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4181 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4182 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4183 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4184 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4185 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4186 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4187 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4188 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4189 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4190 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4191 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4192 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4194 /* also handle MIDI SPP because its so common */
4196 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4197 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4198 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4201 boost::shared_ptr<Controllable>
4202 Session::solo_cut_control() const
4204 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4205 * controls in Ardour that currently get presented to the user in the GUI that require
4206 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4208 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4209 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4212 return _solo_cut_control;
4216 Session::save_snapshot_name (const std::string & n)
4218 /* assure Stateful::_instant_xml is loaded
4219 * add_instant_xml() only adds to existing data and defaults
4220 * to use an empty Tree otherwise
4222 instant_xml ("LastUsedSnapshot");
4224 XMLNode last_used_snapshot ("LastUsedSnapshot");
4225 last_used_snapshot.set_property ("name", n);
4226 add_instant_xml (last_used_snapshot, false);
4230 Session::set_snapshot_name (const std::string & n)
4232 _current_snapshot_name = n;
4233 save_snapshot_name (n);
4237 Session::rename (const std::string& new_name)
4239 string legal_name = legalize_for_path (new_name);
4245 string const old_sources_root = _session_dir->sources_root();
4247 if (!_writable || (_state_of_the_state & CannotSave)) {
4248 error << _("Cannot rename read-only session.") << endmsg;
4249 return 0; // don't show "messed up" warning
4251 if (record_status() == Recording) {
4252 error << _("Cannot rename session while recording") << endmsg;
4253 return 0; // don't show "messed up" warning
4256 StateProtector stp (this);
4261 * interchange subdirectory
4265 * Backup files are left unchanged and not renamed.
4268 /* Windows requires that we close all files before attempting the
4269 * rename. This works on other platforms, but isn't necessary there.
4270 * Leave it in place for all platforms though, since it may help
4271 * catch issues that could arise if the way Source files work ever
4272 * change (since most developers are not using Windows).
4275 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4276 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4282 /* pass one: not 100% safe check that the new directory names don't
4286 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4290 /* this is a stupid hack because Glib::path_get_dirname() is
4291 * lexical-only, and so passing it /a/b/c/ gives a different
4292 * result than passing it /a/b/c ...
4295 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4296 oldstr = oldstr.substr (0, oldstr.length() - 1);
4299 string base = Glib::path_get_dirname (oldstr);
4301 newstr = Glib::build_filename (base, legal_name);
4303 cerr << "Looking for " << newstr << endl;
4305 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4306 cerr << " exists\n";
4315 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4321 /* this is a stupid hack because Glib::path_get_dirname() is
4322 * lexical-only, and so passing it /a/b/c/ gives a different
4323 * result than passing it /a/b/c ...
4326 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4327 oldstr = oldstr.substr (0, oldstr.length() - 1);
4330 string base = Glib::path_get_dirname (oldstr);
4331 newstr = Glib::build_filename (base, legal_name);
4333 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4335 cerr << "Rename " << oldstr << " => " << newstr << endl;
4336 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4337 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4338 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4342 /* Reset path in "session dirs" */
4347 /* reset primary SessionDirectory object */
4350 (*_session_dir) = newstr;
4355 /* now rename directory below session_dir/interchange */
4357 string old_interchange_dir;
4358 string new_interchange_dir;
4360 /* use newstr here because we renamed the path
4361 * (folder/directory) that used to be oldstr to newstr above
4364 v.push_back (newstr);
4365 v.push_back (interchange_dir_name);
4366 v.push_back (Glib::path_get_basename (oldstr));
4368 old_interchange_dir = Glib::build_filename (v);
4371 v.push_back (newstr);
4372 v.push_back (interchange_dir_name);
4373 v.push_back (legal_name);
4375 new_interchange_dir = Glib::build_filename (v);
4377 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4379 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4380 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4381 old_interchange_dir, new_interchange_dir,
4384 error << string_compose (_("renaming %s as %2 failed (%3)"),
4385 old_interchange_dir, new_interchange_dir,
4394 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4395 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4397 cerr << "Rename " << oldstr << " => " << newstr << endl;
4399 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4400 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4401 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4407 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4409 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4410 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4412 cerr << "Rename " << oldstr << " => " << newstr << endl;
4414 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4415 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4416 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4421 /* remove old name from recent sessions */
4422 remove_recent_sessions (_path);
4425 /* update file source paths */
4427 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4428 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4430 string p = fs->path ();
4431 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4433 SourceFactory::setup_peakfile(i->second, true);
4437 set_snapshot_name (new_name);
4442 /* save state again to get everything just right */
4444 save_state (_current_snapshot_name);
4446 /* add to recent sessions */
4448 store_recent_sessions (new_name, _path);
4454 Session::parse_stateful_loading_version (const std::string& version)
4456 if (version.empty ()) {
4457 /* no version implies very old version of Ardour */
4461 if (version.find ('.') != string::npos) {
4462 /* old school version format */
4463 if (version[0] == '2') {
4469 return string_to<int32_t>(version);
4474 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4476 bool found_sr = false;
4477 bool found_data_format = false;
4478 std::string version;
4479 program_version = "";
4481 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4485 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4489 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4492 xmlFreeParserCtxt(ctxt);
4496 xmlNodePtr node = xmlDocGetRootElement(doc);
4499 xmlFreeParserCtxt(ctxt);
4504 /* sample rate & version*/
4507 for (attr = node->properties; attr; attr = attr->next) {
4508 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4509 version = std::string ((char*)attr->children->content);
4511 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4512 sample_rate = atoi ((char*)attr->children->content);
4517 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4521 node = node->children;
4522 while (node != NULL) {
4523 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4524 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4526 program_version = string ((const char*)val);
4527 size_t sep = program_version.find_first_of("-");
4528 if (sep != string::npos) {
4529 program_version = program_version.substr (0, sep);
4534 if (strcmp((const char*) node->name, "Config")) {
4538 for (node = node->children; node; node = node->next) {
4539 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4540 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4542 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4545 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4547 found_data_format = true;
4548 } catch (PBD::unknown_enumeration& e) {}
4558 xmlFreeParserCtxt(ctxt);
4561 return (found_sr && found_data_format) ? 0 : 1;
4565 Session::get_snapshot_from_instant (const std::string& session_dir)
4567 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4569 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4574 if (!tree.read (instant_xml_path)) {
4578 XMLProperty const * prop;
4579 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4580 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4581 return prop->value();
4587 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4588 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4591 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4595 SourcePathMap source_path_map;
4597 boost::shared_ptr<AudioFileSource> afs;
4602 Glib::Threads::Mutex::Lock lm (source_lock);
4604 cerr << " total sources = " << sources.size();
4606 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4607 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4613 if (fs->within_session()) {
4617 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4618 source_path_map[fs->path()].push_back (fs);
4620 SeveralFileSources v;
4622 source_path_map.insert (make_pair (fs->path(), v));
4628 cerr << " fsources = " << total << endl;
4630 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4632 /* tell caller where we are */
4634 string old_path = i->first;
4636 callback (n, total, old_path);
4638 cerr << old_path << endl;
4642 switch (i->second.front()->type()) {
4643 case DataType::AUDIO:
4644 new_path = new_audio_source_path_for_embedded (old_path);
4647 case DataType::MIDI:
4648 /* XXX not implemented yet */
4652 if (new_path.empty()) {
4656 cerr << "Move " << old_path << " => " << new_path << endl;
4658 if (!copy_file (old_path, new_path)) {
4659 cerr << "failed !\n";
4663 /* make sure we stop looking in the external
4664 dir/folder. Remember, this is an all-or-nothing
4665 operations, it doesn't merge just some files.
4667 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4669 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4670 (*f)->set_path (new_path);
4675 save_state ("", false, false);
4681 bool accept_all_files (string const &, void *)
4687 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4689 /* 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.
4694 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4696 // old_path must be in within_session ()
4697 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4699 v.push_back (new_session_folder); /* full path */
4700 v.push_back (interchange_dir_name);
4701 v.push_back (new_session_name); /* just one directory/folder */
4702 v.push_back (typedir);
4703 v.push_back (Glib::path_get_basename (old_path));
4705 return Glib::build_filename (v);
4709 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4712 v.push_back (new_session_folder); /* full path */
4713 v.push_back (interchange_dir_name);
4714 v.push_back (new_session_name);
4715 v.push_back (ARDOUR::sound_dir_name);
4716 v.push_back (filename);
4718 return Glib::build_filename (v);
4722 Session::save_as (SaveAs& saveas)
4724 vector<string> files;
4725 string current_folder = Glib::path_get_dirname (_path);
4726 string new_folder = legalize_for_path (saveas.new_name);
4727 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4728 int64_t total_bytes = 0;
4732 int32_t internal_file_cnt = 0;
4734 vector<string> do_not_copy_extensions;
4735 do_not_copy_extensions.push_back (statefile_suffix);
4736 do_not_copy_extensions.push_back (pending_suffix);
4737 do_not_copy_extensions.push_back (backup_suffix);
4738 do_not_copy_extensions.push_back (temp_suffix);
4739 do_not_copy_extensions.push_back (history_suffix);
4741 /* get total size */
4743 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4745 /* need to clear this because
4746 * find_files_matching_filter() is cumulative
4751 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4753 all += files.size();
4755 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4757 g_stat ((*i).c_str(), &gsb);
4758 total_bytes += gsb.st_size;
4762 /* save old values so we can switch back if we are not switching to the new session */
4764 string old_path = _path;
4765 string old_name = _name;
4766 string old_snapshot = _current_snapshot_name;
4767 string old_sd = _session_dir->root_path();
4768 vector<string> old_search_path[DataType::num_types];
4769 string old_config_search_path[DataType::num_types];
4771 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4772 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4773 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4774 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4776 /* switch session directory */
4778 (*_session_dir) = to_dir;
4780 /* create new tree */
4782 if (!_session_dir->create()) {
4783 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4788 /* copy all relevant files. Find each location in session_dirs,
4789 * and copy files from there to target.
4792 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4794 /* need to clear this because
4795 * find_files_matching_filter() is cumulative
4800 const size_t prefix_len = (*sd).path.size();
4802 /* Work just on the files within this session dir */
4804 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4806 /* add dir separator to protect against collisions with
4807 * track names (e.g. track named "audiofiles" or
4811 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4812 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4813 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4815 /* copy all the files. Handling is different for media files
4816 than others because of the *silly* subtree we have below the interchange
4817 folder. That really was a bad idea, but I'm not fixing it as part of
4818 implementing ::save_as().
4821 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4823 std::string from = *i;
4826 string filename = Glib::path_get_basename (from);
4827 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4828 if (filename == ".DS_STORE") {
4833 if (from.find (audiofile_dir_string) != string::npos) {
4835 /* audio file: only copy if asked */
4837 if (saveas.include_media && saveas.copy_media) {
4839 string to = make_new_media_path (*i, to_dir, new_folder);
4841 info << "media file copying from " << from << " to " << to << endmsg;
4843 if (!copy_file (from, to)) {
4844 throw Glib::FileError (Glib::FileError::IO_ERROR,
4845 string_compose(_("\ncopying \"%1\" failed !"), from));
4849 /* we found media files inside the session folder */
4851 internal_file_cnt++;
4853 } else if (from.find (midifile_dir_string) != string::npos) {
4855 /* midi file: always copy unless
4856 * creating an empty new session
4859 if (saveas.include_media) {
4861 string to = make_new_media_path (*i, to_dir, new_folder);
4863 info << "media file copying from " << from << " to " << to << endmsg;
4865 if (!copy_file (from, to)) {
4866 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4870 /* we found media files inside the session folder */
4872 internal_file_cnt++;
4874 } else if (from.find (analysis_dir_string) != string::npos) {
4876 /* make sure analysis dir exists in
4877 * new session folder, but we're not
4878 * copying analysis files here, see
4882 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4887 /* normal non-media file. Don't copy state, history, etc.
4890 bool do_copy = true;
4892 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4893 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4894 /* end of filename matches extension, do not copy file */
4900 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4901 /* don't copy peakfiles if
4902 * we're not copying media
4908 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4910 info << "attempting to make directory/folder " << to << endmsg;
4912 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4913 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4916 info << "attempting to copy " << from << " to " << to << endmsg;
4918 if (!copy_file (from, to)) {
4919 throw Glib::FileError (Glib::FileError::IO_ERROR,
4920 string_compose(_("\ncopying \"%1\" failed !"), from));
4925 /* measure file size even if we're not going to copy so that our Progress
4926 signals are correct, since we included these do-not-copy files
4927 in the computation of the total size and file count.
4931 g_stat (from.c_str(), &gsb);
4932 copied += gsb.st_size;
4935 double fraction = (double) copied / total_bytes;
4937 bool keep_going = true;
4939 if (saveas.copy_media) {
4941 /* no need or expectation of this if
4942 * media is not being copied, because
4943 * it will be fast(ish).
4946 /* tell someone "X percent, file M of N"; M is one-based */
4948 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4956 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4962 /* copy optional folders, if any */
4964 string old = plugins_dir ();
4965 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4966 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4967 copy_files (old, newdir);
4970 old = externals_dir ();
4971 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4972 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4973 copy_files (old, newdir);
4976 old = automation_dir ();
4977 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4978 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4979 copy_files (old, newdir);
4982 if (saveas.include_media) {
4984 if (saveas.copy_media) {
4985 #ifndef PLATFORM_WINDOWS
4986 /* There are problems with analysis files on
4987 * Windows, because they used a colon in their
4988 * names as late as 4.0. Colons are not legal
4989 * under Windows even if NTFS allows them.
4991 * This is a tricky problem to solve so for
4992 * just don't copy these files. They will be
4993 * regenerated as-needed anyway, subject to the
4994 * existing issue that the filenames will be
4995 * rejected by Windows, which is a separate
4996 * problem (though related).
4999 /* only needed if we are copying media, since the
5000 * analysis data refers to media data
5003 old = analysis_dir ();
5004 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5005 string newdir = Glib::build_filename (to_dir, "analysis");
5006 copy_files (old, newdir);
5008 #endif /* PLATFORM_WINDOWS */
5013 set_snapshot_name (saveas.new_name);
5014 _name = saveas.new_name;
5016 if (saveas.include_media && !saveas.copy_media) {
5018 /* reset search paths of the new session (which we're pretending to be right now) to
5019 include the original session search path, so we can still find all audio.
5022 if (internal_file_cnt) {
5023 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5024 ensure_search_path_includes (*s, DataType::AUDIO);
5025 cerr << "be sure to include " << *s << " for audio" << endl;
5028 /* we do not do this for MIDI because we copy
5029 all MIDI files if saveas.include_media is
5035 bool was_dirty = dirty ();
5037 save_default_options ();
5039 if (saveas.copy_media && saveas.copy_external) {
5040 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5041 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5045 saveas.final_session_folder_name = _path;
5047 store_recent_sessions (_name, _path);
5049 if (!saveas.switch_to) {
5051 /* save the new state */
5053 save_state ("", false, false, !saveas.include_media);
5055 /* switch back to the way things were */
5059 set_snapshot_name (old_snapshot);
5061 (*_session_dir) = old_sd;
5067 if (internal_file_cnt) {
5068 /* reset these to their original values */
5069 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5070 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5075 /* prune session dirs, and update disk space statistics
5080 session_dirs.clear ();
5081 session_dirs.push_back (sp);
5082 refresh_disk_space ();
5084 _writable = exists_and_writable (_path);
5086 /* ensure that all existing tracks reset their current capture source paths
5088 reset_write_sources (true, true);
5090 /* creating new write sources marks the session as
5091 dirty. If the new session is empty, then
5092 save_state() thinks we're saving a template and will
5093 not mark the session as clean. So do that here,
5094 before we save state.
5097 if (!saveas.include_media) {
5098 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5101 save_state ("", false, false, !saveas.include_media);
5103 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5104 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5107 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5108 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5114 if (fs->within_session()) {
5115 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5116 fs->set_path (newpath);
5121 } catch (Glib::FileError& e) {
5123 saveas.failure_message = e.what();
5125 /* recursively remove all the directories */
5127 remove_directory (to_dir);
5135 saveas.failure_message = _("unknown reason");
5137 /* recursively remove all the directories */
5139 remove_directory (to_dir);
5149 static void set_progress (Progress* p, size_t n, size_t t)
5151 p->set_progress (float (n) / float(t));
5155 Session::archive_session (const std::string& dest,
5156 const std::string& name,
5157 ArchiveEncode compress_audio,
5158 FileArchive::CompressionLevel compression_level,
5159 bool only_used_sources,
5162 if (dest.empty () || name.empty ()) {
5166 /* We are going to temporarily change some source properties,
5167 * don't allow any concurrent saves (periodic or otherwise */
5168 Glib::Threads::Mutex::Lock lm (save_source_lock);
5170 disable_record (false);
5172 /* save current values */
5173 string old_path = _path;
5174 string old_name = _name;
5175 string old_snapshot = _current_snapshot_name;
5176 string old_sd = _session_dir->root_path();
5177 string old_config_search_path[DataType::num_types];
5178 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5179 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5181 /* ensure that session-path is included in search-path */
5183 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5184 if ((*sd).path == old_path) {
5192 /* create temporary dir to save session to */
5193 #ifdef PLATFORM_WINDOWS
5194 char tmp[256] = "C:\\TEMP\\";
5195 GetTempPath (sizeof (tmp), tmp);
5197 char const* tmp = getenv("TMPDIR");
5202 if ((strlen (tmp) + 21) > 1024) {
5207 strcpy (tmptpl, tmp);
5208 strcat (tmptpl, "ardourarchive-XXXXXX");
5209 char* tmpdir = g_mkdtemp (tmptpl);
5215 std::string to_dir = std::string (tmpdir);
5217 /* switch session directory temporarily */
5218 (*_session_dir) = to_dir;
5220 if (!_session_dir->create()) {
5221 (*_session_dir) = old_sd;
5222 remove_directory (to_dir);
5226 /* prepare archive */
5227 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5229 PBD::ScopedConnectionList progress_connection;
5230 PBD::FileArchive ar (archive);
5232 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5235 /* collect files to archive */
5236 std::map<string,string> filemap;
5238 vector<string> do_not_copy_extensions;
5239 do_not_copy_extensions.push_back (statefile_suffix);
5240 do_not_copy_extensions.push_back (pending_suffix);
5241 do_not_copy_extensions.push_back (backup_suffix);
5242 do_not_copy_extensions.push_back (temp_suffix);
5243 do_not_copy_extensions.push_back (history_suffix);
5245 vector<string> blacklist_dirs;
5246 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5247 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5248 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5249 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5250 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5251 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5253 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5254 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5255 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5257 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5258 if (only_used_sources) {
5259 playlists->sync_all_regions_with_regions ();
5260 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5263 /* collect audio sources for this session, calc total size for encoding
5264 * add option to only include *used* sources (see Session::cleanup_sources)
5266 size_t total_size = 0;
5268 Glib::Threads::Mutex::Lock lm (source_lock);
5270 /* build a list of used names */
5271 std::set<std::string> audio_file_names;
5272 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5273 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5276 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5277 if (!afs || afs->readable_length () == 0) {
5280 if (only_used_sources) {
5284 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5288 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5291 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5292 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5295 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5296 if (!afs || afs->readable_length () == 0) {
5300 if (only_used_sources) {
5304 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5309 std::string from = afs->path();
5311 if (compress_audio != NO_ENCODE) {
5312 total_size += afs->readable_length ();
5314 /* copy files as-is */
5315 if (!afs->within_session()) {
5316 string to = Glib::path_get_basename (from);
5318 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5319 * - avoid conflict with files existing in interchange
5320 * - avoid conflict with other embedded sources
5322 if (audio_file_names.find (to) == audio_file_names.end ()) {
5323 // we need a new name, add a '-<num>' before the '.<ext>'
5324 string bn = to.substr (0, to.find_last_of ('.'));
5325 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5326 to = bn + "-1" + ext;
5328 while (audio_file_names.find (to) == audio_file_names.end ()) {
5329 to = bump_name_once (to, '-');
5332 audio_file_names.insert (to);
5333 filemap[from] = make_new_audio_path (to, name, name);
5335 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5337 orig_origin[afs] = afs->origin ();
5338 afs->set_origin ("");
5341 filemap[from] = make_new_media_path (from, name, name);
5348 if (compress_audio != NO_ENCODE) {
5350 progress->set_progress (2); // set to "encoding"
5351 progress->set_progress (0);
5354 Glib::Threads::Mutex::Lock lm (source_lock);
5355 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5356 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5359 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5360 if (!afs || afs->readable_length () == 0) {
5364 if (only_used_sources) {
5368 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5373 orig_sources[afs] = afs->path();
5374 orig_gain[afs] = afs->gain();
5376 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5378 std::string channelsuffix = "";
5379 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5380 /* embedded external multi-channel files are converted to multiple-mono */
5381 channelsuffix = string_compose ("-c%1", afs->channel ());
5383 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5384 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5386 /* avoid name collisions of external files with same name */
5387 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5388 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5390 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5391 new_path = bump_name_once (new_path, '-');
5395 progress->descend ((float)afs->readable_length () / total_size);
5399 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5400 afs->replace_file (new_path);
5401 afs->set_gain (ns->gain(), true);
5404 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5408 progress->ascend ();
5414 progress->set_progress (-1); // set to "archiving"
5415 progress->set_progress (0);
5418 /* index files relevant for this session */
5419 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5420 vector<string> files;
5422 size_t prefix_len = (*sd).path.size();
5423 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5427 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5429 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5430 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5431 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5433 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5434 std::string from = *i;
5437 string filename = Glib::path_get_basename (from);
5438 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5439 if (filename == ".DS_STORE") {
5444 if (from.find (audiofile_dir_string) != string::npos) {
5446 } else if (from.find (midifile_dir_string) != string::npos) {
5447 filemap[from] = make_new_media_path (from, name, name);
5448 } else if (from.find (videofile_dir_string) != string::npos) {
5449 filemap[from] = make_new_media_path (from, name, name);
5451 bool do_copy = true;
5452 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5453 if (from.find (*v) != string::npos) {
5458 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5459 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5466 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5472 /* write session file */
5474 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5476 save_state (name, false, false, false, true, only_used_sources);
5478 save_default_options ();
5480 size_t prefix_len = _path.size();
5481 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5485 /* collect session-state files */
5486 vector<string> files;
5487 do_not_copy_extensions.clear ();
5488 do_not_copy_extensions.push_back (history_suffix);
5490 blacklist_dirs.clear ();
5491 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5493 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5494 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5495 std::string from = *i;
5496 bool do_copy = true;
5497 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5498 if (from.find (*v) != string::npos) {
5503 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5504 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5510 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5514 /* restore original values */
5517 set_snapshot_name (old_snapshot);
5518 (*_session_dir) = old_sd;
5519 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5520 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5522 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5523 i->first->set_origin (i->second);
5525 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5526 i->first->replace_file (i->second);
5528 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5529 i->first->set_gain (i->second, true);
5532 int rv = ar.create (filemap, compression_level);
5533 remove_directory (to_dir);
5539 Session::undo (uint32_t n)
5541 if (actively_recording()) {
5549 Session::redo (uint32_t n)
5551 if (actively_recording()) {