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/types_convert.h"
131 #include "ardour/user_bundle.h"
132 #include "ardour/vca.h"
133 #include "ardour/vca_manager.h"
135 #include "control_protocol/control_protocol.h"
137 #include "LuaBridge/LuaBridge.h"
139 #include "pbd/i18n.h"
143 using namespace ARDOUR;
146 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
149 Session::pre_engine_init (string fullpath)
151 if (fullpath.empty()) {
153 throw failed_constructor();
156 /* discover canonical fullpath */
158 _path = canonical_path(fullpath);
161 if (Profile->get_trx() ) {
162 // Waves TracksLive has a usecase of session replacement with a new one.
163 // We should check session state file (<session_name>.ardour) existance
164 // to determine if the session is new or not
166 string full_session_name = Glib::build_filename( fullpath, _name );
167 full_session_name += statefile_suffix;
169 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
171 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
174 /* finish initialization that can't be done in a normal C++ constructor
178 timerclear (&last_mmc_step);
179 g_atomic_int_set (&processing_prohibited, 0);
180 g_atomic_int_set (&_record_status, Disabled);
181 g_atomic_int_set (&_playback_load, 100);
182 g_atomic_int_set (&_capture_load, 100);
184 _all_route_group->set_active (true, this);
186 if (config.get_use_video_sync()) {
187 waiting_for_sync_offset = true;
189 waiting_for_sync_offset = false;
192 last_rr_session_dir = session_dirs.begin();
194 set_history_depth (Config->get_history_depth());
196 /* default: assume simple stereo speaker configuration */
198 _speakers->setup_default_speakers (2);
200 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
201 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
202 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
203 add_controllable (_solo_cut_control);
205 /* These are all static "per-class" signals */
207 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
208 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
209 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
210 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
211 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
213 /* stop IO objects from doing stuff until we're ready for them */
215 Delivery::disable_panners ();
216 IO::disable_connecting ();
220 Session::post_engine_init ()
222 BootMessage (_("Set block size and sample rate"));
224 set_block_size (_engine.samples_per_cycle());
225 set_sample_rate (_engine.sample_rate());
227 BootMessage (_("Using configuration"));
229 _midi_ports = new MidiPortManager;
231 MIDISceneChanger* msc;
233 _scene_changer = msc = new MIDISceneChanger (*this);
234 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
235 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
237 boost::function<samplecnt_t(void)> timer_func (boost::bind (&Session::audible_sample, this, (bool*)(0)));
238 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
240 setup_midi_machine_control ();
242 if (_butler->start_thread()) {
243 error << _("Butler did not start") << endmsg;
247 if (start_midi_thread ()) {
248 error << _("MIDI I/O thread did not start") << endmsg;
252 setup_click_sounds (0);
253 setup_midi_control ();
255 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
256 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
259 /* tempo map requires sample rate knowledge */
262 _tempo_map = new TempoMap (_current_sample_rate);
263 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
264 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
265 } catch (std::exception const & e) {
266 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
269 error << _("Unknown exception during session setup") << endmsg;
274 /* MidiClock requires a tempo map */
277 midi_clock = new MidiClockTicker ();
278 midi_clock->set_session (this);
280 /* crossfades require sample rate knowledge */
282 SndFileSource::setup_standard_crossfades (*this, sample_rate());
283 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
284 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
286 DiskReader::allocate_working_buffers();
287 refresh_disk_space ();
289 /* we're finally ready to call set_state() ... all objects have
290 * been created, the engine is running.
295 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
296 error << _("Could not set session state from XML") << endmsg;
299 } catch (PBD::unknown_enumeration& e) {
300 error << _("Session state: ") << e.what() << endmsg;
304 // set_state() will call setup_raid_path(), but if it's a new session we need
305 // to call setup_raid_path() here.
306 setup_raid_path (_path);
311 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
312 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
314 Config->map_parameters (ff);
315 config.map_parameters (ft);
316 _butler->map_parameters ();
318 /* Reset all panners */
320 Delivery::reset_panners ();
322 /* this will cause the CPM to instantiate any protocols that are in use
323 * (or mandatory), which will pass it this Session, and then call
324 * set_state() on each instantiated protocol to match stored state.
327 ControlProtocolManager::instance().set_session (this);
329 /* This must be done after the ControlProtocolManager set_session above,
330 as it will set states for ports which the ControlProtocolManager creates.
333 // XXX set state of MIDI::Port's
334 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
336 /* And this must be done after the MIDI::Manager::set_port_states as
337 * it will try to make connections whose details are loaded by set_port_states.
342 /* Let control protocols know that we are now all connected, so they
343 * could start talking to surfaces if they want to.
346 ControlProtocolManager::instance().midi_connectivity_established ();
348 if (_is_new && !no_auto_connect()) {
349 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
350 auto_connect_master_bus ();
353 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
355 /* update latencies */
357 initialize_latencies ();
359 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
360 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
361 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
363 } catch (AudioEngine::PortRegistrationFailure& err) {
364 error << err.what() << endmsg;
366 } catch (std::exception const & e) {
367 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
370 error << _("Unknown exception during session setup") << endmsg;
374 BootMessage (_("Reset Remote Controls"));
376 // send_full_time_code (0);
377 _engine.transport_locate (0);
379 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
380 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
382 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
385 /* initial program change will be delivered later; see ::config_changed() */
387 _state_of_the_state = Clean;
389 Port::set_connecting_blocked (false);
391 DirtyChanged (); /* EMIT SIGNAL */
395 } else if (state_was_pending) {
397 remove_pending_capture_state ();
398 state_was_pending = false;
401 /* Now, finally, we can fill the playback buffers */
403 BootMessage (_("Filling playback buffers"));
405 boost::shared_ptr<RouteList> rl = routes.reader();
406 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
407 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
408 if (trk && !trk->is_private_route()) {
409 trk->seek (_transport_sample, true);
417 Session::session_loaded ()
421 _state_of_the_state = Clean;
423 DirtyChanged (); /* EMIT SIGNAL */
427 } else if (state_was_pending) {
429 remove_pending_capture_state ();
430 state_was_pending = false;
433 /* Now, finally, we can fill the playback buffers */
435 BootMessage (_("Filling playback buffers"));
436 force_locate (_transport_sample, false);
440 Session::raid_path () const
442 Searchpath raid_search_path;
444 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
445 raid_search_path += (*i).path;
448 return raid_search_path.to_string ();
452 Session::setup_raid_path (string path)
461 session_dirs.clear ();
463 Searchpath search_path(path);
464 Searchpath sound_search_path;
465 Searchpath midi_search_path;
467 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
469 sp.blocks = 0; // not needed
470 session_dirs.push_back (sp);
472 SessionDirectory sdir(sp.path);
474 sound_search_path += sdir.sound_path ();
475 midi_search_path += sdir.midi_path ();
478 // reset the round-robin soundfile path thingie
479 last_rr_session_dir = session_dirs.begin();
483 Session::path_is_within_session (const std::string& path)
485 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
486 if (PBD::path_is_within (i->path, path)) {
494 Session::ensure_subdirs ()
498 dir = session_directory().peak_path();
500 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
501 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
505 dir = session_directory().sound_path();
507 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
508 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
512 dir = session_directory().midi_path();
514 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
515 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
519 dir = session_directory().dead_path();
521 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
522 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
526 dir = session_directory().export_path();
528 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
529 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
533 dir = analysis_dir ();
535 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
536 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
540 dir = plugins_dir ();
542 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
543 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
547 dir = externals_dir ();
549 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
550 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
557 /** @param session_template directory containing session template, or empty.
558 * Caller must not hold process lock.
561 Session::create (const string& session_template, BusProfile* bus_profile)
563 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
564 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
568 if (ensure_subdirs ()) {
572 _writable = exists_and_writable (_path);
574 if (!session_template.empty()) {
575 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
577 FILE* in = g_fopen (in_path.c_str(), "rb");
580 /* no need to call legalize_for_path() since the string
581 * in session_template is already a legal path name
583 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
585 FILE* out = g_fopen (out_path.c_str(), "wb");
589 stringstream new_session;
592 size_t charsRead = fread (buf, sizeof(char), 1024, in);
595 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
600 if (charsRead == 0) {
603 new_session.write (buf, charsRead);
607 string file_contents = new_session.str();
608 size_t writeSize = file_contents.length();
609 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
610 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
618 if (!ARDOUR::Profile->get_trx()) {
619 /* Copy plugin state files from template to new session */
620 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
621 copy_recurse (template_plugins, plugins_dir ());
627 error << string_compose (_("Could not open %1 for writing session template"), out_path)
634 error << string_compose (_("Could not open session template %1 for reading"), in_path)
641 if (Profile->get_trx()) {
643 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
644 * Remember that this is a brand new session. Sessions
645 * loaded from saved state will get this range from the saved state.
648 set_session_range_location (0, 0);
650 /* Initial loop location, from absolute zero, length 10 seconds */
652 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
653 _locations->add (loc, true);
654 set_auto_loop_location (loc);
657 _state_of_the_state = Clean;
659 /* set up Master Out and Monitor Out if necessary */
663 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
664 if (bus_profile->master_out_channels) {
665 int rv = add_master_bus (count);
671 if (Config->get_use_monitor_bus())
672 add_monitor_section ();
680 Session::maybe_write_autosave()
682 if (dirty() && record_status() != Recording) {
683 save_state("", true);
688 Session::remove_pending_capture_state ()
690 std::string pending_state_file_path(_session_dir->root_path());
692 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
694 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
696 if (g_remove (pending_state_file_path.c_str()) != 0) {
697 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
698 pending_state_file_path, g_strerror (errno)) << endmsg;
702 /** Rename a state file.
703 * @param old_name Old snapshot name.
704 * @param new_name New snapshot name.
707 Session::rename_state (string old_name, string new_name)
709 if (old_name == _current_snapshot_name || old_name == _name) {
710 /* refuse to rename the current snapshot or the "main" one */
714 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
715 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
717 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
718 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
720 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
721 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
722 old_name, new_name, g_strerror(errno)) << endmsg;
726 /** Remove a state file.
727 * @param snapshot_name Snapshot name.
730 Session::remove_state (string snapshot_name)
732 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
733 // refuse to remove the current snapshot or the "main" one
737 std::string xml_path(_session_dir->root_path());
739 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
741 if (!create_backup_file (xml_path)) {
742 // don't remove it if a backup can't be made
743 // create_backup_file will log the error.
748 if (g_remove (xml_path.c_str()) != 0) {
749 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
750 xml_path, g_strerror (errno)) << endmsg;
753 StateSaved (snapshot_name); /* EMIT SIGNAL */
756 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
758 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only, bool for_archive, bool only_used_assets)
760 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
763 std::string xml_path(_session_dir->root_path());
765 /* prevent concurrent saves from different threads */
767 Glib::Threads::Mutex::Lock lm (save_state_lock);
768 Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK);
773 if (!_writable || (_state_of_the_state & CannotSave)) {
777 if (g_atomic_int_get(&_suspend_save)) {
781 _save_queued = false;
783 snapshot_t fork_state = NormalSave;
784 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) {
785 /* snapshot, close midi */
786 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
790 const int64_t save_start_time = g_get_monotonic_time();
793 /* tell sources we're saving first, in case they write out to a new file
794 * which should be saved with the state rather than the old one */
795 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
797 i->second->session_saved();
798 } catch (Evoral::SMF::FileError& e) {
799 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
803 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, for_archive);
805 SessionSaveUnderway (); /* EMIT SIGNAL */
807 bool mark_as_clean = true;
808 if (!snapshot_name.empty() && !switch_to_snapshot) {
809 mark_as_clean = false;
813 mark_as_clean = false;
814 tree.set_root (&get_template());
816 tree.set_root (&state (false, fork_state, only_used_assets));
819 if (snapshot_name.empty()) {
820 snapshot_name = _current_snapshot_name;
821 } else if (switch_to_snapshot) {
822 set_snapshot_name (snapshot_name);
825 assert (!snapshot_name.empty());
829 /* proper save: use statefile_suffix (.ardour in English) */
831 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
833 /* make a backup copy of the old file */
835 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
836 // create_backup_file will log the error
842 /* pending save: use pending_suffix (.pending in English) */
843 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
846 std::string tmp_path(_session_dir->root_path());
847 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
850 cerr << "actually writing state to " << tmp_path << endl;
853 if (!tree.write (tmp_path)) {
854 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
855 if (g_remove (tmp_path.c_str()) != 0) {
856 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
857 tmp_path, g_strerror (errno)) << endmsg;
864 cerr << "renaming state to " << xml_path << endl;
867 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
868 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
869 tmp_path, xml_path, g_strerror(errno)) << endmsg;
870 if (g_remove (tmp_path.c_str()) != 0) {
871 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
872 tmp_path, g_strerror (errno)) << endmsg;
878 //Mixbus auto-backup mechanism
879 if(Profile->get_mixbus()) {
880 if (pending) { //"pending" save means it's a backup, or some other non-user-initiated save; a good time to make a backup
881 // make a serialized safety backup
882 // (will make one periodically but only one per hour is left on disk)
883 // these backup files go into a separated folder
886 struct tm local_time;
888 localtime_r (&n, &local_time);
889 strftime (timebuf, sizeof(timebuf), "%y-%m-%d.%H", &local_time);
890 std::string save_path(session_directory().backup_path());
891 save_path += G_DIR_SEPARATOR;
892 save_path += legalize_for_path(_current_snapshot_name);
894 save_path += timebuf;
895 save_path += statefile_suffix;
896 if ( !tree.write (save_path) )
897 error << string_compose(_("Could not save backup file at path \"%1\" (%2)"),
898 save_path, g_strerror (errno)) << endmsg;
901 StateSaved (snapshot_name); /* EMIT SIGNAL */
904 if (!pending && !for_archive) {
906 save_history (snapshot_name);
909 bool was_dirty = dirty();
911 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
914 DirtyChanged (); /* EMIT SIGNAL */
918 StateSaved (snapshot_name); /* EMIT SIGNAL */
922 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
923 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
929 Session::restore_state (string snapshot_name)
932 if (load_state (snapshot_name) == 0) {
933 set_state (*state_tree->root(), Stateful::loading_state_version);
937 // unknown_enumeration
945 Session::load_state (string snapshot_name)
950 state_was_pending = false;
952 /* check for leftover pending state from a crashed capture attempt */
954 std::string xmlpath(_session_dir->root_path());
955 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
957 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
959 /* there is pending state from a crashed capture attempt */
961 boost::optional<int> r = AskAboutPendingState();
962 if (r.get_value_or (1)) {
963 state_was_pending = true;
967 if (!state_was_pending) {
968 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
971 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
972 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
973 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
974 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
979 state_tree = new XMLTree;
983 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
985 if (!state_tree->read (xmlpath)) {
986 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
992 XMLNode const & root (*state_tree->root());
994 if (root.name() != X_("Session")) {
995 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
1001 std::string version;
1002 root.get_property ("version", version);
1003 Stateful::loading_state_version = parse_stateful_loading_version (version);
1005 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
1006 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
1007 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
1010 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1012 std::string backup_path(_session_dir->root_path());
1013 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1014 backup_path = Glib::build_filename (backup_path, backup_filename);
1016 // only create a backup for a given statefile version once
1018 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1020 VersionMismatch (xmlpath, backup_path);
1022 if (!copy_file (xmlpath, backup_path)) {;
1028 save_snapshot_name (snapshot_name);
1034 Session::load_options (const XMLNode& node)
1036 config.set_variables (node);
1041 Session::save_default_options ()
1043 return config.save_state();
1047 Session::get_state ()
1049 /* this is not directly called, but required by PBD::Stateful */
1051 return state (false, NormalSave);
1055 Session::get_template ()
1057 /* if we don't disable rec-enable, diskstreams
1058 will believe they need to store their capture
1059 sources in their state node.
1062 disable_record (false);
1064 return state (true, NormalSave);
1067 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1068 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1071 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1073 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1076 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1080 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1083 XMLNode* node = new XMLNode("TrackState"); // XXX
1086 PlaylistSet playlists; // SessionPlaylists
1089 // these will work with new_route_from_template()
1090 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1091 child = node->add_child ("Routes");
1092 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1093 if ((*i)->is_auditioner()) {
1096 if ((*i)->is_master() || (*i)->is_monitor()) {
1099 child->add_child_nocopy ((*i)->get_state());
1100 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1102 playlists.insert (track->playlist ());
1106 // on load, Regions in the playlists need to resolve and map Source-IDs
1107 // also playlist needs to be merged or created with new-name..
1108 // ... and Diskstream in tracks adjusted to use the correct playlist
1109 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1110 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1111 child->add_child_nocopy ((*i)->get_state ());
1112 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1113 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1114 const Region::SourceList& sl = (*s)->sources ();
1115 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1116 sources.insert (*sli);
1121 child = node->add_child ("Sources");
1122 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1123 child->add_child_nocopy ((*i)->get_state ());
1124 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1126 #ifdef PLATFORM_WINDOWS
1129 string p = fs->path ();
1130 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1134 std::string sn = Glib::build_filename (path, "share.axml");
1137 tree.set_root (node);
1138 return tree.write (sn.c_str());
1142 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
1144 pl->deep_sources (*all_sources);
1149 struct route_id_compare {
1151 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1153 return r1->id () < r2->id ();
1159 Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets)
1162 XMLNode* node = new XMLNode("Session");
1165 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1167 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1169 child = node->add_child ("ProgramVersion");
1170 child->set_property("created-with", created_with);
1172 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1173 child->set_property("modified-with", modified_with);
1175 /* store configuration settings */
1177 if (!save_template) {
1179 node->set_property ("name", _name);
1180 node->set_property ("sample-rate", _base_sample_rate);
1182 if (session_dirs.size() > 1) {
1186 vector<space_and_path>::iterator i = session_dirs.begin();
1187 vector<space_and_path>::iterator next;
1189 ++i; /* skip the first one */
1193 while (i != session_dirs.end()) {
1197 if (next != session_dirs.end()) {
1198 p += G_SEARCHPATH_SEPARATOR;
1207 child = node->add_child ("Path");
1208 child->add_content (p);
1210 node->set_property ("end-is-free", _session_range_end_is_free);
1213 /* save the ID counter */
1215 node->set_property ("id-counter", ID::counter());
1217 node->set_property ("name-counter", name_id_counter ());
1219 /* save the event ID counter */
1221 node->set_property ("event-counter", Evoral::event_id_counter());
1223 /* save the VCA counter */
1225 node->set_property ("vca-counter", VCA::get_next_vca_number());
1227 /* various options */
1229 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1230 if (!midi_port_nodes.empty()) {
1231 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1232 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1233 midi_port_stuff->add_child_nocopy (**n);
1235 node->add_child_nocopy (*midi_port_stuff);
1238 XMLNode& cfgxml (config.get_variables ());
1239 if (save_template) {
1240 /* exclude search-paths from template */
1241 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1242 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1243 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1245 node->add_child_nocopy (cfgxml);
1247 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1249 child = node->add_child ("Sources");
1251 if (!save_template) {
1252 Glib::Threads::Mutex::Lock sl (source_lock);
1254 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1256 if (only_used_assets) {
1257 playlists->sync_all_regions_with_regions ();
1258 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1261 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1263 /* Don't save information about non-file Sources, or
1264 * about non-destructive file sources that are empty
1265 * and unused by any regions.
1267 boost::shared_ptr<FileSource> fs;
1269 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1273 if (!fs->destructive()) {
1274 if (fs->empty() && !fs->used()) {
1279 if (only_used_assets) {
1280 /* skip only unused audio files */
1281 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1282 if (afs && !afs->used()) {
1285 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1290 if (snapshot_type != NormalSave && fs->within_session ()) {
1291 /* copy MIDI sources to new file
1293 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1294 * because the GUI (midi_region) has a direct pointer to the midi-model
1295 * of the source, as does UndoTransaction.
1297 * On the upside, .mid files are not kept open. The file is only open
1298 * when reading the model initially and when flushing the model to disk:
1299 * source->session_saved () or export.
1301 * We can change the _path of the existing source under the hood, keeping
1302 * all IDs, references and pointers intact.
1304 boost::shared_ptr<SMFSource> ms;
1305 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1306 const std::string ancestor_name = ms->ancestor_name();
1307 const std::string base = PBD::basename_nosuffix(ancestor_name);
1308 const string path = new_midi_source_path (base, false);
1310 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1311 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1312 Source::Lock lm (ms->mutex());
1314 // TODO special-case empty, removable() files: just create a new removable.
1315 // (load + write flushes the model and creates the file)
1317 ms->load_model (lm);
1319 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1320 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1322 if (snapshot_type == SnapshotKeep) {
1323 /* keep working on current session.
1325 * Save snapshot-state with the original filename.
1326 * Switch to use new path for future saves of the main session.
1328 child->add_child_nocopy (ms->get_state());
1332 * ~SMFSource unlinks removable() files.
1334 std::string npath (ms->path ());
1335 ms->replace_file (newsrc->path ());
1336 newsrc->replace_file (npath);
1338 if (snapshot_type == SwitchToSnapshot) {
1339 /* save and switch to snapshot.
1341 * Leave the old file in place (as is).
1342 * Snapshot uses new source directly
1344 child->add_child_nocopy (ms->get_state());
1351 child->add_child_nocopy (siter->second->get_state());
1355 child = node->add_child ("Regions");
1357 if (!save_template) {
1358 Glib::Threads::Mutex::Lock rl (region_lock);
1360 if (!only_used_assets) {
1361 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1362 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1363 boost::shared_ptr<Region> r = i->second;
1364 /* only store regions not attached to playlists */
1365 if (r->playlist() == 0) {
1366 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1367 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1369 child->add_child_nocopy (r->get_state ());
1375 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1377 if (!cassocs.empty()) {
1378 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1380 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1381 if (i->first->playlist () == 0 && only_used_assets) {
1384 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1385 can->set_property (X_("copy"), i->first->id());
1386 can->set_property (X_("original"), i->second->id());
1387 ca->add_child_nocopy (*can);
1388 /* see above, child is still "Regions" here */
1389 if (i->second->playlist() == 0 && only_used_assets) {
1390 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1391 child->add_child_nocopy (ar->get_basic_state ());
1393 child->add_child_nocopy (ar->get_state ());
1400 if (!save_template) {
1402 node->add_child_nocopy (_selection->get_state());
1405 node->add_child_nocopy (_locations->get_state());
1408 Locations loc (*this);
1409 const bool was_dirty = dirty();
1410 // for a template, just create a new Locations, populate it
1411 // with the default start and end, and get the state for that.
1412 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1413 range->set (max_samplepos, 0);
1415 XMLNode& locations_state = loc.get_state();
1417 if (ARDOUR::Profile->get_trx() && _locations) {
1418 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1419 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1420 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1421 locations_state.add_child_nocopy ((*i)->get_state ());
1425 node->add_child_nocopy (locations_state);
1427 /* adding a location above will have marked the session
1428 * dirty. This is an artifact, so fix it if the session wasn't
1433 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1437 child = node->add_child ("Bundles");
1439 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1440 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1441 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1443 child->add_child_nocopy (b->get_state());
1448 node->add_child_nocopy (_vca_manager->get_state());
1450 child = node->add_child ("Routes");
1452 boost::shared_ptr<RouteList> r = routes.reader ();
1454 route_id_compare cmp;
1455 RouteList xml_node_order (*r);
1456 xml_node_order.sort (cmp);
1458 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1459 if (!(*i)->is_auditioner()) {
1460 if (save_template) {
1461 child->add_child_nocopy ((*i)->get_template());
1463 child->add_child_nocopy ((*i)->get_state());
1469 playlists->add_state (node, save_template, !only_used_assets);
1471 child = node->add_child ("RouteGroups");
1472 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1473 child->add_child_nocopy ((*i)->get_state());
1477 XMLNode* gain_child = node->add_child ("Click");
1478 gain_child->add_child_nocopy (_click_io->get_state ());
1479 gain_child->add_child_nocopy (_click_gain->get_state ());
1483 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1484 ltc_input_child->add_child_nocopy (_ltc_input->get_state ());
1488 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1489 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1492 node->add_child_nocopy (_speakers->get_state());
1493 node->add_child_nocopy (_tempo_map->get_state());
1494 node->add_child_nocopy (get_control_protocol_state());
1497 node->add_child_copy (*_extra_xml);
1501 Glib::Threads::Mutex::Lock lm (lua_lock);
1504 luabridge::LuaRef savedstate ((*_lua_save)());
1505 saved = savedstate.cast<std::string>();
1507 lua.collect_garbage ();
1510 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1511 std::string b64s (b64);
1514 XMLNode* script_node = new XMLNode (X_("Script"));
1515 script_node->set_property (X_("lua"), LUA_VERSION);
1516 script_node->add_content (b64s);
1517 node->add_child_nocopy (*script_node);
1524 Session::get_control_protocol_state ()
1526 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1527 return cpm.get_state();
1531 Session::set_state (const XMLNode& node, int version)
1538 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1540 if (node.name() != X_("Session")) {
1541 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1545 node.get_property ("name", _name);
1547 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1549 _nominal_sample_rate = _base_sample_rate;
1551 assert (AudioEngine::instance()->running ());
1552 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1553 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1554 if (r.get_value_or (0)) {
1560 created_with = "unknown";
1561 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1562 child->get_property (X_("created-with"), created_with);
1565 setup_raid_path(_session_dir->root_path());
1567 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1570 if (node.get_property (X_("id-counter"), counter)) {
1571 ID::init_counter (counter);
1573 /* old sessions used a timebased counter, so fake
1574 * the startup ID counter based on a standard
1579 ID::init_counter (now);
1582 if (node.get_property (X_("name-counter"), counter)) {
1583 init_name_id_counter (counter);
1586 if (node.get_property (X_("event-counter"), counter)) {
1587 Evoral::init_event_id_counter (counter);
1590 if (node.get_property (X_("vca-counter"), counter)) {
1591 VCA::set_next_vca_number (counter);
1593 VCA::set_next_vca_number (1);
1596 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1597 _midi_ports->set_midi_port_states (child->children());
1600 IO::disable_connecting ();
1602 Stateful::save_extra_xml (node);
1604 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1605 load_options (*child);
1606 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1607 load_options (*child);
1609 error << _("Session: XML state has no options section") << endmsg;
1612 if (version >= 3000) {
1613 if ((child = find_named_node (node, "Metadata")) == 0) {
1614 warning << _("Session: XML state has no metadata section") << endmsg;
1615 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1620 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1621 _speakers->set_state (*child, version);
1624 if ((child = find_named_node (node, "Sources")) == 0) {
1625 error << _("Session: XML state has no sources section") << endmsg;
1627 } else if (load_sources (*child)) {
1631 if ((child = find_named_node (node, "TempoMap")) == 0) {
1632 error << _("Session: XML state has no Tempo Map section") << endmsg;
1634 } else if (_tempo_map->set_state (*child, version)) {
1638 if ((child = find_named_node (node, "Locations")) == 0) {
1639 error << _("Session: XML state has no locations section") << endmsg;
1641 } else if (_locations->set_state (*child, version)) {
1645 locations_changed ();
1647 if (_session_range_location) {
1648 AudioFileSource::set_header_position_offset (_session_range_location->start());
1651 if ((child = find_named_node (node, "Regions")) == 0) {
1652 error << _("Session: XML state has no Regions section") << endmsg;
1654 } else if (load_regions (*child)) {
1658 if ((child = find_named_node (node, "Playlists")) == 0) {
1659 error << _("Session: XML state has no playlists section") << endmsg;
1661 } else if (playlists->load (*this, *child)) {
1665 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1667 } else if (playlists->load_unused (*this, *child)) {
1671 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1672 if (load_compounds (*child)) {
1677 if (version >= 3000) {
1678 if ((child = find_named_node (node, "Bundles")) == 0) {
1679 warning << _("Session: XML state has no bundles section") << endmsg;
1682 /* We can't load Bundles yet as they need to be able
1683 * to convert from port names to Port objects, which can't happen until
1685 _bundle_xml_node = new XMLNode (*child);
1689 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1690 _vca_manager->set_state (*child, version);
1693 if ((child = find_named_node (node, "Routes")) == 0) {
1694 error << _("Session: XML state has no routes section") << endmsg;
1696 } else if (load_routes (*child, version)) {
1700 /* Now that we have Routes and masters loaded, connect them if appropriate */
1702 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1704 if (version >= 3000) {
1706 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1707 error << _("Session: XML state has no route groups section") << endmsg;
1709 } else if (load_route_groups (*child, version)) {
1713 } else if (version < 3000) {
1715 if ((child = find_named_node (node, "EditGroups")) == 0) {
1716 error << _("Session: XML state has no edit groups section") << endmsg;
1718 } else if (load_route_groups (*child, version)) {
1722 if ((child = find_named_node (node, "MixGroups")) == 0) {
1723 error << _("Session: XML state has no mix groups section") << endmsg;
1725 } else if (load_route_groups (*child, version)) {
1730 if ((child = find_named_node (node, "Click")) == 0) {
1731 warning << _("Session: XML state has no click section") << endmsg;
1732 } else if (_click_io) {
1733 setup_click_state (&node);
1736 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1737 ControlProtocolManager::instance().set_state (*child, version);
1740 if ((child = find_named_node (node, "Script"))) {
1741 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1742 if (!(*n)->is_content ()) { continue; }
1744 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1746 Glib::Threads::Mutex::Lock lm (lua_lock);
1747 (*_lua_load)(std::string ((const char*)buf, size));
1748 } catch (luabridge::LuaException const& e) {
1749 cerr << "LuaException:" << e.what () << endl;
1755 if ((child = find_named_node (node, X_("Selection")))) {
1756 _selection->set_state (*child, version);
1759 update_route_record_state ();
1761 /* here beginneth the second phase ... */
1762 set_snapshot_name (_current_snapshot_name);
1764 StateReady (); /* EMIT SIGNAL */
1777 Session::load_routes (const XMLNode& node, int version)
1780 XMLNodeConstIterator niter;
1781 RouteList new_routes;
1783 nlist = node.children();
1787 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1789 boost::shared_ptr<Route> route;
1791 if (version < 3000) {
1792 route = XMLRouteFactory_2X (**niter, version);
1793 } else if (version < 5000) {
1794 route = XMLRouteFactory_3X (**niter, version);
1796 route = XMLRouteFactory (**niter, version);
1800 error << _("Session: cannot create Route from XML description.") << endmsg;
1804 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1806 new_routes.push_back (route);
1809 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1811 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1813 BootMessage (_("Finished adding tracks/busses"));
1818 boost::shared_ptr<Route>
1819 Session::XMLRouteFactory (const XMLNode& node, int version)
1821 boost::shared_ptr<Route> ret;
1823 if (node.name() != "Route") {
1827 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1830 pl_prop = node.property (X_("midi-playlist"));
1833 DataType type = DataType::AUDIO;
1834 node.get_property("default-type", type);
1836 assert (type != DataType::NIL);
1840 /* has at least 1 playlist, therefore a track ... */
1842 boost::shared_ptr<Track> track;
1844 if (type == DataType::AUDIO) {
1845 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1847 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1850 if (track->init()) {
1854 if (track->set_state (node, version)) {
1858 BOOST_MARK_TRACK (track);
1862 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1863 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1866 if (r->init () == 0 && r->set_state (node, version) == 0) {
1867 BOOST_MARK_ROUTE (r);
1875 boost::shared_ptr<Route>
1876 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1878 boost::shared_ptr<Route> ret;
1880 if (node.name() != "Route") {
1884 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1886 DataType type = DataType::AUDIO;
1887 node.get_property("default-type", type);
1889 assert (type != DataType::NIL);
1893 boost::shared_ptr<Track> track;
1895 if (type == DataType::AUDIO) {
1896 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1898 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1901 if (track->init()) {
1905 if (track->set_state (node, version)) {
1909 BOOST_MARK_TRACK (track);
1913 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1914 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1916 if (r->init () == 0 && r->set_state (node, version) == 0) {
1917 BOOST_MARK_ROUTE (r);
1925 boost::shared_ptr<Route>
1926 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1928 boost::shared_ptr<Route> ret;
1930 if (node.name() != "Route") {
1934 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1936 ds_prop = node.property (X_("diskstream"));
1939 DataType type = DataType::AUDIO;
1940 node.get_property("default-type", type);
1942 assert (type != DataType::NIL);
1946 /* see comment in current ::set_state() regarding diskstream
1947 * state and DiskReader/DiskWRiter.
1950 error << _("Could not find diskstream for route") << endmsg;
1951 return boost::shared_ptr<Route> ();
1953 boost::shared_ptr<Track> track;
1955 if (type == DataType::AUDIO) {
1956 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1958 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1961 if (track->init()) {
1965 if (track->set_state (node, version)) {
1969 BOOST_MARK_TRACK (track);
1973 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1974 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1976 if (r->init () == 0 && r->set_state (node, version) == 0) {
1977 BOOST_MARK_ROUTE (r);
1986 Session::load_regions (const XMLNode& node)
1989 XMLNodeConstIterator niter;
1990 boost::shared_ptr<Region> region;
1992 nlist = node.children();
1996 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1997 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1998 error << _("Session: cannot create Region from XML description.");
1999 XMLProperty const * name = (**niter).property("name");
2002 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
2013 Session::load_compounds (const XMLNode& node)
2015 XMLNodeList calist = node.children();
2016 XMLNodeConstIterator caiter;
2017 XMLProperty const * caprop;
2019 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
2020 XMLNode* ca = *caiter;
2024 if ((caprop = ca->property (X_("original"))) == 0) {
2027 orig_id = caprop->value();
2029 if ((caprop = ca->property (X_("copy"))) == 0) {
2032 copy_id = caprop->value();
2034 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2035 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2037 if (!orig || !copy) {
2038 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2044 RegionFactory::add_compound_association (orig, copy);
2051 Session::load_nested_sources (const XMLNode& node)
2054 XMLNodeConstIterator niter;
2056 nlist = node.children();
2058 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2059 if ((*niter)->name() == "Source") {
2061 /* it may already exist, so don't recreate it unnecessarily
2064 XMLProperty const * prop = (*niter)->property (X_("id"));
2066 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2070 ID source_id (prop->value());
2072 if (!source_by_id (source_id)) {
2075 SourceFactory::create (*this, **niter, true);
2077 catch (failed_constructor& err) {
2078 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2085 boost::shared_ptr<Region>
2086 Session::XMLRegionFactory (const XMLNode& node, bool full)
2088 XMLProperty const * type = node.property("type");
2092 const XMLNodeList& nlist = node.children();
2094 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2095 XMLNode *child = (*niter);
2096 if (child->name() == "NestedSource") {
2097 load_nested_sources (*child);
2101 if (!type || type->value() == "audio") {
2102 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2103 } else if (type->value() == "midi") {
2104 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2107 } catch (failed_constructor& err) {
2108 return boost::shared_ptr<Region> ();
2111 return boost::shared_ptr<Region> ();
2114 boost::shared_ptr<AudioRegion>
2115 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2117 XMLProperty const * prop;
2118 boost::shared_ptr<Source> source;
2119 boost::shared_ptr<AudioSource> as;
2121 SourceList master_sources;
2122 uint32_t nchans = 1;
2125 if (node.name() != X_("Region")) {
2126 return boost::shared_ptr<AudioRegion>();
2129 node.get_property (X_("channels"), nchans);
2131 if ((prop = node.property ("name")) == 0) {
2132 cerr << "no name for this region\n";
2136 if ((prop = node.property (X_("source-0"))) == 0) {
2137 if ((prop = node.property ("source")) == 0) {
2138 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2139 return boost::shared_ptr<AudioRegion>();
2143 PBD::ID s_id (prop->value());
2145 if ((source = source_by_id (s_id)) == 0) {
2146 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2147 return boost::shared_ptr<AudioRegion>();
2150 as = boost::dynamic_pointer_cast<AudioSource>(source);
2152 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2153 return boost::shared_ptr<AudioRegion>();
2156 sources.push_back (as);
2158 /* pickup other channels */
2160 for (uint32_t n=1; n < nchans; ++n) {
2161 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2162 if ((prop = node.property (buf)) != 0) {
2164 PBD::ID id2 (prop->value());
2166 if ((source = source_by_id (id2)) == 0) {
2167 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2168 return boost::shared_ptr<AudioRegion>();
2171 as = boost::dynamic_pointer_cast<AudioSource>(source);
2173 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2174 return boost::shared_ptr<AudioRegion>();
2176 sources.push_back (as);
2180 for (uint32_t n = 0; n < nchans; ++n) {
2181 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2182 if ((prop = node.property (buf)) != 0) {
2184 PBD::ID id2 (prop->value());
2186 if ((source = source_by_id (id2)) == 0) {
2187 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2188 return boost::shared_ptr<AudioRegion>();
2191 as = boost::dynamic_pointer_cast<AudioSource>(source);
2193 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2194 return boost::shared_ptr<AudioRegion>();
2196 master_sources.push_back (as);
2201 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2203 /* a final detail: this is the one and only place that we know how long missing files are */
2205 if (region->whole_file()) {
2206 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2207 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2209 sfp->set_length (region->length());
2214 if (!master_sources.empty()) {
2215 if (master_sources.size() != nchans) {
2216 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2218 region->set_master_sources (master_sources);
2226 catch (failed_constructor& err) {
2227 return boost::shared_ptr<AudioRegion>();
2231 boost::shared_ptr<MidiRegion>
2232 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2234 XMLProperty const * prop;
2235 boost::shared_ptr<Source> source;
2236 boost::shared_ptr<MidiSource> ms;
2239 if (node.name() != X_("Region")) {
2240 return boost::shared_ptr<MidiRegion>();
2243 if ((prop = node.property ("name")) == 0) {
2244 cerr << "no name for this region\n";
2248 if ((prop = node.property (X_("source-0"))) == 0) {
2249 if ((prop = node.property ("source")) == 0) {
2250 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2251 return boost::shared_ptr<MidiRegion>();
2255 PBD::ID s_id (prop->value());
2257 if ((source = source_by_id (s_id)) == 0) {
2258 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2259 return boost::shared_ptr<MidiRegion>();
2262 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2264 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2265 return boost::shared_ptr<MidiRegion>();
2268 sources.push_back (ms);
2271 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2272 /* a final detail: this is the one and only place that we know how long missing files are */
2274 if (region->whole_file()) {
2275 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2276 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2278 sfp->set_length (region->length());
2286 catch (failed_constructor& err) {
2287 return boost::shared_ptr<MidiRegion>();
2292 Session::get_sources_as_xml ()
2295 XMLNode* node = new XMLNode (X_("Sources"));
2296 Glib::Threads::Mutex::Lock lm (source_lock);
2298 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2299 node->add_child_nocopy (i->second->get_state());
2306 Session::reset_write_sources (bool mark_write_complete, bool force)
2308 boost::shared_ptr<RouteList> rl = routes.reader();
2309 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2310 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2312 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2313 tr->reset_write_sources(mark_write_complete, force);
2314 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2320 Session::load_sources (const XMLNode& node)
2323 XMLNodeConstIterator niter;
2324 /* don't need this but it stops some
2325 * versions of gcc complaining about
2326 * discarded return values.
2328 boost::shared_ptr<Source> source;
2330 nlist = node.children();
2333 std::map<std::string, std::string> relocation;
2335 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2336 #ifdef PLATFORM_WINDOWS
2340 XMLNode srcnode (**niter);
2341 bool try_replace_abspath = true;
2345 #ifdef PLATFORM_WINDOWS
2346 // do not show "insert media" popups (files embedded from removable media).
2347 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2349 if ((source = XMLSourceFactory (srcnode)) == 0) {
2350 error << _("Session: cannot create Source from XML description.") << endmsg;
2352 #ifdef PLATFORM_WINDOWS
2353 SetErrorMode(old_mode);
2356 } catch (MissingSource& err) {
2357 #ifdef PLATFORM_WINDOWS
2358 SetErrorMode(old_mode);
2361 /* try previous abs path replacements first */
2362 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2363 std::string dir = Glib::path_get_dirname (err.path);
2364 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2365 if (rl != relocation.end ()) {
2366 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2367 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2368 srcnode.set_property ("origin", newpath);
2369 try_replace_abspath = false;
2376 _missing_file_replacement = "";
2378 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2379 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2380 PROGRAM_NAME) << endmsg;
2384 if (!no_questions_about_missing_files) {
2385 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2390 switch (user_choice) {
2392 /* user added a new search location
2393 * or selected a new absolute path,
2395 if (Glib::path_is_absolute (err.path)) {
2396 if (!_missing_file_replacement.empty ()) {
2397 /* replace origin, in XML */
2398 std::string newpath = Glib::build_filename (
2399 _missing_file_replacement, Glib::path_get_basename (err.path));
2400 srcnode.set_property ("origin", newpath);
2401 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2402 _missing_file_replacement = "";
2409 /* user asked to quit the entire session load */
2413 no_questions_about_missing_files = true;
2417 no_questions_about_missing_files = true;
2424 case DataType::AUDIO:
2425 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2428 case DataType::MIDI:
2429 /* The MIDI file is actually missing so
2430 * just create a new one in the same
2431 * location. Do not announce its
2435 if (!Glib::path_is_absolute (err.path)) {
2436 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2438 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2443 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2444 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2445 /* reset ID to match the missing one */
2446 source->set_id (**niter);
2447 /* Now we can announce it */
2448 SourceFactory::SourceCreated (source);
2459 boost::shared_ptr<Source>
2460 Session::XMLSourceFactory (const XMLNode& node)
2462 if (node.name() != "Source") {
2463 return boost::shared_ptr<Source>();
2467 /* note: do peak building in another thread when loading session state */
2468 return SourceFactory::create (*this, node, true);
2471 catch (failed_constructor& err) {
2472 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2473 return boost::shared_ptr<Source>();
2478 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2480 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2484 bool absolute_path = Glib::path_is_absolute (template_name);
2486 /* directory to put the template in */
2487 std::string template_dir_path;
2489 if (!absolute_path) {
2490 std::string user_template_dir(user_template_directory());
2492 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2493 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2494 user_template_dir, g_strerror (errno)) << endmsg;
2498 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2500 template_dir_path = template_name;
2503 if (!ARDOUR::Profile->get_trx()) {
2504 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2505 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2506 template_dir_path) << endmsg;
2510 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2511 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2512 template_dir_path, g_strerror (errno)) << endmsg;
2518 std::string template_file_path;
2520 if (ARDOUR::Profile->get_trx()) {
2521 template_file_path = template_name;
2523 if (absolute_path) {
2524 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2526 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2530 SessionSaveUnderway (); /* EMIT SIGNAL */
2535 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2536 root = &get_template ();
2539 root->remove_nodes_and_delete (X_("description"));
2541 if (!description.empty()) {
2542 XMLNode* desc = new XMLNode (X_("description"));
2543 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2544 desc->add_child_nocopy (*desc_cont);
2546 root->add_child_nocopy (*desc);
2549 tree.set_root (root);
2551 if (!tree.write (template_file_path)) {
2552 error << _("template not saved") << endmsg;
2556 store_recent_templates (template_file_path);
2562 Session::refresh_disk_space ()
2564 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2566 Glib::Threads::Mutex::Lock lm (space_lock);
2568 /* get freespace on every FS that is part of the session path */
2570 _total_free_4k_blocks = 0;
2571 _total_free_4k_blocks_uncertain = false;
2573 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2574 #if defined(__NetBSD__)
2575 struct statvfs statfsbuf;
2577 statvfs (i->path.c_str(), &statfsbuf);
2579 struct statfs statfsbuf;
2581 statfs (i->path.c_str(), &statfsbuf);
2583 double const scale = statfsbuf.f_bsize / 4096.0;
2585 /* See if this filesystem is read-only */
2586 struct statvfs statvfsbuf;
2587 statvfs (i->path.c_str(), &statvfsbuf);
2589 /* f_bavail can be 0 if it is undefined for whatever
2590 filesystem we are looking at; Samba shares mounted
2591 via GVFS are an example of this.
2593 if (statfsbuf.f_bavail == 0) {
2594 /* block count unknown */
2596 i->blocks_unknown = true;
2597 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2598 /* read-only filesystem */
2600 i->blocks_unknown = false;
2602 /* read/write filesystem with known space */
2603 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2604 i->blocks_unknown = false;
2607 _total_free_4k_blocks += i->blocks;
2608 if (i->blocks_unknown) {
2609 _total_free_4k_blocks_uncertain = true;
2612 #elif defined PLATFORM_WINDOWS
2613 vector<string> scanned_volumes;
2614 vector<string>::iterator j;
2615 vector<space_and_path>::iterator i;
2616 DWORD nSectorsPerCluster, nBytesPerSector,
2617 nFreeClusters, nTotalClusters;
2621 _total_free_4k_blocks = 0;
2623 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2624 strncpy (disk_drive, (*i).path.c_str(), 3);
2628 volume_found = false;
2629 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2631 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2632 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2633 i->blocks = (uint32_t)(nFreeBytes / 4096);
2635 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2636 if (0 == j->compare(disk_drive)) {
2637 volume_found = true;
2642 if (!volume_found) {
2643 scanned_volumes.push_back(disk_drive);
2644 _total_free_4k_blocks += i->blocks;
2649 if (0 == _total_free_4k_blocks) {
2650 strncpy (disk_drive, path().c_str(), 3);
2653 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2655 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2656 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2657 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2664 Session::get_best_session_directory_for_new_audio ()
2666 vector<space_and_path>::iterator i;
2667 string result = _session_dir->root_path();
2669 /* handle common case without system calls */
2671 if (session_dirs.size() == 1) {
2675 /* OK, here's the algorithm we're following here:
2677 We want to select which directory to use for
2678 the next file source to be created. Ideally,
2679 we'd like to use a round-robin process so as to
2680 get maximum performance benefits from splitting
2681 the files across multiple disks.
2683 However, in situations without much diskspace, an
2684 RR approach may end up filling up a filesystem
2685 with new files while others still have space.
2686 Its therefore important to pay some attention to
2687 the freespace in the filesystem holding each
2688 directory as well. However, if we did that by
2689 itself, we'd keep creating new files in the file
2690 system with the most space until it was as full
2691 as all others, thus negating any performance
2692 benefits of this RAID-1 like approach.
2694 So, we use a user-configurable space threshold. If
2695 there are at least 2 filesystems with more than this
2696 much space available, we use RR selection between them.
2697 If not, then we pick the filesystem with the most space.
2699 This gets a good balance between the two
2703 refresh_disk_space ();
2705 int free_enough = 0;
2707 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2708 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2713 if (free_enough >= 2) {
2714 /* use RR selection process, ensuring that the one
2718 i = last_rr_session_dir;
2721 if (++i == session_dirs.end()) {
2722 i = session_dirs.begin();
2725 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2726 SessionDirectory sdir(i->path);
2727 if (sdir.create ()) {
2729 last_rr_session_dir = i;
2734 } while (i != last_rr_session_dir);
2738 /* pick FS with the most freespace (and that
2739 seems to actually work ...)
2742 vector<space_and_path> sorted;
2743 space_and_path_ascending_cmp cmp;
2745 sorted = session_dirs;
2746 sort (sorted.begin(), sorted.end(), cmp);
2748 for (i = sorted.begin(); i != sorted.end(); ++i) {
2749 SessionDirectory sdir(i->path);
2750 if (sdir.create ()) {
2752 last_rr_session_dir = i;
2762 Session::automation_dir () const
2764 return Glib::build_filename (_path, automation_dir_name);
2768 Session::analysis_dir () const
2770 return Glib::build_filename (_path, analysis_dir_name);
2774 Session::plugins_dir () const
2776 return Glib::build_filename (_path, plugins_dir_name);
2780 Session::externals_dir () const
2782 return Glib::build_filename (_path, externals_dir_name);
2786 Session::load_bundles (XMLNode const & node)
2788 XMLNodeList nlist = node.children();
2789 XMLNodeConstIterator niter;
2793 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2794 if ((*niter)->name() == "InputBundle") {
2795 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2796 } else if ((*niter)->name() == "OutputBundle") {
2797 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2799 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2808 Session::load_route_groups (const XMLNode& node, int version)
2810 XMLNodeList nlist = node.children();
2811 XMLNodeConstIterator niter;
2815 if (version >= 3000) {
2817 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2818 if ((*niter)->name() == "RouteGroup") {
2819 RouteGroup* rg = new RouteGroup (*this, "");
2820 add_route_group (rg);
2821 rg->set_state (**niter, version);
2825 } else if (version < 3000) {
2827 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2828 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2829 RouteGroup* rg = new RouteGroup (*this, "");
2830 add_route_group (rg);
2831 rg->set_state (**niter, version);
2840 state_file_filter (const string &str, void* /*arg*/)
2842 return (str.length() > strlen(statefile_suffix) &&
2843 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2847 remove_end(string state)
2849 string statename(state);
2851 string::size_type start,end;
2852 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2853 statename = statename.substr (start+1);
2856 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2857 end = statename.length();
2860 return string(statename.substr (0, end));
2864 Session::possible_states (string path)
2866 vector<string> states;
2867 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2869 transform(states.begin(), states.end(), states.begin(), remove_end);
2871 sort (states.begin(), states.end());
2877 Session::possible_states () const
2879 return possible_states(_path);
2883 Session::new_route_group (const std::string& name)
2885 RouteGroup* rg = NULL;
2887 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2888 if ((*i)->name () == name) {
2895 rg = new RouteGroup (*this, name);
2896 add_route_group (rg);
2902 Session::add_route_group (RouteGroup* g)
2904 _route_groups.push_back (g);
2905 route_group_added (g); /* EMIT SIGNAL */
2907 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2908 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2909 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2915 Session::remove_route_group (RouteGroup& rg)
2917 list<RouteGroup*>::iterator i;
2919 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2920 _route_groups.erase (i);
2923 route_group_removed (); /* EMIT SIGNAL */
2927 /** Set a new order for our route groups, without adding or removing any.
2928 * @param groups Route group list in the new order.
2931 Session::reorder_route_groups (list<RouteGroup*> groups)
2933 _route_groups = groups;
2935 route_groups_reordered (); /* EMIT SIGNAL */
2941 Session::route_group_by_name (string name)
2943 list<RouteGroup *>::iterator i;
2945 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2946 if ((*i)->name() == name) {
2954 Session::all_route_group() const
2956 return *_all_route_group;
2960 Session::add_commands (vector<Command*> const & cmds)
2962 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2968 Session::add_command (Command* const cmd)
2970 assert (_current_trans);
2971 DEBUG_UNDO_HISTORY (
2972 string_compose ("Current Undo Transaction %1, adding command: %2",
2973 _current_trans->name (),
2975 _current_trans->add_command (cmd);
2978 PBD::StatefulDiffCommand*
2979 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2981 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2987 Session::begin_reversible_command (const string& name)
2989 begin_reversible_command (g_quark_from_string (name.c_str ()));
2992 /** Begin a reversible command using a GQuark to identify it.
2993 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2994 * but there must be as many begin...()s as there are commit...()s.
2997 Session::begin_reversible_command (GQuark q)
2999 /* If nested begin/commit pairs are used, we create just one UndoTransaction
3000 to hold all the commands that are committed. This keeps the order of
3001 commands correct in the history.
3004 if (_current_trans == 0) {
3005 DEBUG_UNDO_HISTORY (string_compose (
3006 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
3008 /* start a new transaction */
3009 assert (_current_trans_quarks.empty ());
3010 _current_trans = new UndoTransaction();
3011 _current_trans->set_name (g_quark_to_string (q));
3013 DEBUG_UNDO_HISTORY (
3014 string_compose ("Begin Reversible Command, current transaction: %1",
3015 _current_trans->name ()));
3018 _current_trans_quarks.push_front (q);
3022 Session::abort_reversible_command ()
3024 if (_current_trans != 0) {
3025 DEBUG_UNDO_HISTORY (
3026 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
3027 _current_trans->clear();
3028 delete _current_trans;
3030 _current_trans_quarks.clear();
3035 Session::commit_reversible_command (Command *cmd)
3037 assert (_current_trans);
3038 assert (!_current_trans_quarks.empty ());
3043 DEBUG_UNDO_HISTORY (
3044 string_compose ("Current Undo Transaction %1, adding command: %2",
3045 _current_trans->name (),
3047 _current_trans->add_command (cmd);
3050 DEBUG_UNDO_HISTORY (
3051 string_compose ("Commit Reversible Command, current transaction: %1",
3052 _current_trans->name ()));
3054 _current_trans_quarks.pop_front ();
3056 if (!_current_trans_quarks.empty ()) {
3057 DEBUG_UNDO_HISTORY (
3058 string_compose ("Commit Reversible Command, transaction is not "
3059 "top-level, current transaction: %1",
3060 _current_trans->name ()));
3061 /* the transaction we're committing is not the top-level one */
3065 if (_current_trans->empty()) {
3066 /* no commands were added to the transaction, so just get rid of it */
3067 DEBUG_UNDO_HISTORY (
3068 string_compose ("Commit Reversible Command, No commands were "
3069 "added to current transaction: %1",
3070 _current_trans->name ()));
3071 delete _current_trans;
3076 gettimeofday (&now, 0);
3077 _current_trans->set_timestamp (now);
3079 _history.add (_current_trans);
3084 accept_all_audio_files (const string& path, void* /*arg*/)
3086 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3090 if (!AudioFileSource::safe_audio_file_extension (path)) {
3098 accept_all_midi_files (const string& path, void* /*arg*/)
3100 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3104 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3105 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3106 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3110 accept_all_state_files (const string& path, void* /*arg*/)
3112 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3116 std::string const statefile_ext (statefile_suffix);
3117 if (path.length() >= statefile_ext.length()) {
3118 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3125 Session::find_all_sources (string path, set<string>& result)
3130 if (!tree.read (path)) {
3134 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3139 XMLNodeConstIterator niter;
3141 nlist = node->children();
3145 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3147 XMLProperty const * prop;
3149 if ((prop = (*niter)->property (X_("type"))) == 0) {
3153 DataType type (prop->value());
3155 if ((prop = (*niter)->property (X_("name"))) == 0) {
3159 if (Glib::path_is_absolute (prop->value())) {
3160 /* external file, ignore */
3168 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3169 result.insert (found_path);
3177 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3179 vector<string> state_files;
3181 string this_snapshot_path;
3187 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3188 ripped = ripped.substr (0, ripped.length() - 1);
3191 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3193 if (state_files.empty()) {
3198 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3199 this_snapshot_path += statefile_suffix;
3201 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3203 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3205 if (exclude_this_snapshot && *i == this_snapshot_path) {
3206 cerr << "\texcluded\n";
3211 if (find_all_sources (*i, result) < 0) {
3219 struct RegionCounter {
3220 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3221 AudioSourceList::iterator iter;
3222 boost::shared_ptr<Region> region;
3225 RegionCounter() : count (0) {}
3229 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3231 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3232 return r.get_value_or (1);
3236 Session::cleanup_regions ()
3238 bool removed = false;
3239 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3241 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3243 uint32_t used = playlists->region_use_count (i->second);
3245 if (used == 0 && !i->second->automatic ()) {
3246 boost::weak_ptr<Region> w = i->second;
3249 RegionFactory::map_remove (w);
3256 // re-check to remove parent references of compound regions
3257 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3258 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3262 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3263 if (0 == playlists->region_use_count (i->second)) {
3264 boost::weak_ptr<Region> w = i->second;
3266 RegionFactory::map_remove (w);
3273 /* dump the history list */
3280 Session::can_cleanup_peakfiles () const
3282 if (deletion_in_progress()) {
3285 if (!_writable || (_state_of_the_state & CannotSave)) {
3286 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3289 if (record_status() == Recording) {
3290 error << _("Cannot cleanup peak-files while recording") << endmsg;
3297 Session::cleanup_peakfiles ()
3299 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3304 assert (can_cleanup_peakfiles ());
3305 assert (!peaks_cleanup_in_progres());
3307 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3309 int timeout = 5000; // 5 seconds
3310 while (!SourceFactory::files_with_peaks.empty()) {
3311 Glib::usleep (1000);
3312 if (--timeout < 0) {
3313 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3314 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3319 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3320 boost::shared_ptr<AudioSource> as;
3321 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3322 as->close_peakfile();
3326 PBD::clear_directory (session_directory().peak_path());
3328 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3330 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3331 boost::shared_ptr<AudioSource> as;
3332 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3333 SourceFactory::setup_peakfile(as, true);
3340 Session::cleanup_sources (CleanupReport& rep)
3342 // FIXME: needs adaptation to midi
3344 vector<boost::shared_ptr<Source> > dead_sources;
3347 vector<string> candidates;
3348 vector<string> unused;
3349 set<string> sources_used_by_all_snapshots;
3356 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3358 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3360 /* this is mostly for windows which doesn't allow file
3361 * renaming if the file is in use. But we don't special
3362 * case it because we need to know if this causes
3363 * problems, and the easiest way to notice that is to
3364 * keep it in place for all platforms.
3367 request_stop (false);
3369 _butler->wait_until_finished ();
3371 /* consider deleting all unused playlists */
3373 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3378 /* sync the "all regions" property of each playlist with its current state */
3380 playlists->sync_all_regions_with_regions ();
3382 /* find all un-used sources */
3387 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3389 SourceMap::iterator tmp;
3394 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3398 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3399 dead_sources.push_back (i->second);
3400 i->second->drop_references ();
3406 /* build a list of all the possible audio directories for the session */
3408 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3409 SessionDirectory sdir ((*i).path);
3410 asp += sdir.sound_path();
3412 audio_path += asp.to_string();
3415 /* build a list of all the possible midi directories for the session */
3417 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3418 SessionDirectory sdir ((*i).path);
3419 msp += sdir.midi_path();
3421 midi_path += msp.to_string();
3423 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3424 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3426 /* add sources from all other snapshots as "used", but don't use this
3427 snapshot because the state file on disk still references sources we
3428 may have already dropped.
3431 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3433 /* Although the region factory has a list of all regions ever created
3434 * for this session, we're only interested in regions actually in
3435 * playlists right now. So merge all playlist regions lists together.
3437 * This will include the playlists used within compound regions.
3440 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3442 /* add our current source list
3445 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3446 boost::shared_ptr<FileSource> fs;
3447 SourceMap::iterator tmp = i;
3450 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3456 /* this is mostly for windows which doesn't allow file
3457 * renaming if the file is in use. But we do not special
3458 * case it because we need to know if this causes
3459 * problems, and the easiest way to notice that is to
3460 * keep it in place for all platforms.
3465 if (!fs->is_stub()) {
3467 /* Note that we're checking a list of all
3468 * sources across all snapshots with the list
3469 * of sources used by this snapshot.
3472 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3473 /* this source is in use by this snapshot */
3474 sources_used_by_all_snapshots.insert (fs->path());
3475 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3477 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3478 /* this source is NOT in use by this snapshot */
3480 /* remove all related regions from RegionFactory master list */
3482 RegionFactory::remove_regions_using_source (i->second);
3484 /* remove from our current source list
3485 * also. We may not remove it from
3486 * disk, because it may be used by
3487 * other snapshots, but it isn't used inside this
3488 * snapshot anymore, so we don't need a
3499 /* now check each candidate source to see if it exists in the list of
3500 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3503 cerr << "Candidates: " << candidates.size() << endl;
3504 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3506 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3511 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3513 tmppath1 = canonical_path (spath);
3514 tmppath2 = canonical_path ((*i));
3516 cerr << "\t => " << tmppath2 << endl;
3518 if (tmppath1 == tmppath2) {
3525 unused.push_back (spath);
3529 cerr << "Actually unused: " << unused.size() << endl;
3531 if (unused.empty()) {
3537 /* now try to move all unused files into the "dead" directory(ies) */
3539 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3544 /* don't move the file across filesystems, just
3545 * stick it in the `dead_dir_name' directory
3546 * on whichever filesystem it was already on.
3549 if ((*x).find ("/sounds/") != string::npos) {
3551 /* old school, go up 1 level */
3553 newpath = Glib::path_get_dirname (*x); // "sounds"
3554 newpath = Glib::path_get_dirname (newpath); // "session-name"
3558 /* new school, go up 4 levels */
3560 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3561 newpath = Glib::path_get_dirname (newpath); // "session-name"
3562 newpath = Glib::path_get_dirname (newpath); // "interchange"
3563 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3566 newpath = Glib::build_filename (newpath, dead_dir_name);
3568 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3569 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3573 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3575 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3577 /* the new path already exists, try versioning */
3579 char buf[PATH_MAX+1];
3583 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3586 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3587 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3591 if (version == 999) {
3592 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3596 newpath = newpath_v;
3601 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3602 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3603 newpath, g_strerror (errno)) << endmsg;
3607 /* see if there an easy to find peakfile for this file, and remove it. */
3609 string base = Glib::path_get_basename (*x);
3610 base += "%A"; /* this is what we add for the channel suffix of all native files,
3611 * or for the first channel of embedded files. it will miss
3612 * some peakfiles for other channels
3614 string peakpath = construct_peak_filepath (base);
3616 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3617 if (::g_unlink (peakpath.c_str ()) != 0) {
3618 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3619 g_strerror (errno)) << endmsg;
3620 /* try to back out */
3621 ::g_rename (newpath.c_str (), _path.c_str ());
3626 rep.paths.push_back (*x);
3627 rep.space += statbuf.st_size;
3630 /* dump the history list */
3634 /* save state so we don't end up a session file
3635 * referring to non-existent sources.
3642 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3648 Session::cleanup_trash_sources (CleanupReport& rep)
3650 // FIXME: needs adaptation for MIDI
3652 vector<space_and_path>::iterator i;
3658 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3660 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3662 clear_directory (dead_dir, &rep.space, &rep.paths);
3669 Session::set_dirty ()
3671 /* return early if there's nothing to do */
3676 /* never mark session dirty during loading */
3677 if (_state_of_the_state & Loading) {
3681 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3682 DirtyChanged(); /* EMIT SIGNAL */
3686 Session::set_clean ()
3688 bool was_dirty = dirty();
3690 _state_of_the_state = Clean;
3693 DirtyChanged(); /* EMIT SIGNAL */
3698 Session::set_deletion_in_progress ()
3700 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3704 Session::clear_deletion_in_progress ()
3706 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3710 Session::add_controllable (boost::shared_ptr<Controllable> c)
3712 /* this adds a controllable to the list managed by the Session.
3713 this is a subset of those managed by the Controllable class
3714 itself, and represents the only ones whose state will be saved
3715 as part of the session.
3718 Glib::Threads::Mutex::Lock lm (controllables_lock);
3719 controllables.insert (c);
3722 struct null_deleter { void operator()(void const *) const {} };
3725 Session::remove_controllable (Controllable* c)
3727 if (_state_of_the_state & Deletion) {
3731 Glib::Threads::Mutex::Lock lm (controllables_lock);
3733 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3735 if (x != controllables.end()) {
3736 controllables.erase (x);
3740 boost::shared_ptr<Controllable>
3741 Session::controllable_by_id (const PBD::ID& id)
3743 Glib::Threads::Mutex::Lock lm (controllables_lock);
3745 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3746 if ((*i)->id() == id) {
3751 return boost::shared_ptr<Controllable>();
3754 boost::shared_ptr<AutomationControl>
3755 Session::automation_control_by_id (const PBD::ID& id)
3757 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3761 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3764 Stateful::add_instant_xml (node, _path);
3767 if (write_to_config) {
3768 Config->add_instant_xml (node);
3773 Session::instant_xml (const string& node_name)
3775 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3776 if (get_disable_all_loaded_plugins ()) {
3780 return Stateful::instant_xml (node_name, _path);
3784 Session::save_history (string snapshot_name)
3792 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3793 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3797 if (snapshot_name.empty()) {
3798 snapshot_name = _current_snapshot_name;
3801 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3802 const string backup_filename = history_filename + backup_suffix;
3803 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3804 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3806 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3807 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3808 error << _("could not backup old history file, current history not saved") << endmsg;
3813 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3815 if (!tree.write (xml_path))
3817 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3819 if (g_remove (xml_path.c_str()) != 0) {
3820 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3821 xml_path, g_strerror (errno)) << endmsg;
3823 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3824 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3825 backup_path, g_strerror (errno)) << endmsg;
3835 Session::restore_history (string snapshot_name)
3839 if (snapshot_name.empty()) {
3840 snapshot_name = _current_snapshot_name;
3843 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3844 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3846 info << "Loading history from " << xml_path << endmsg;
3848 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3849 info << string_compose (_("%1: no history file \"%2\" for this session."),
3850 _name, xml_path) << endmsg;
3854 if (!tree.read (xml_path)) {
3855 error << string_compose (_("Could not understand session history file \"%1\""),
3856 xml_path) << endmsg;
3863 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3871 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3872 !t->get_property ("tv-usec", tv_usec)) {
3876 UndoTransaction* ut = new UndoTransaction ();
3877 ut->set_name (name);
3881 tv.tv_usec = tv_usec;
3882 ut->set_timestamp(tv);
3884 for (XMLNodeConstIterator child_it = t->children().begin();
3885 child_it != t->children().end(); child_it++)
3887 XMLNode *n = *child_it;
3890 if (n->name() == "MementoCommand" ||
3891 n->name() == "MementoUndoCommand" ||
3892 n->name() == "MementoRedoCommand") {
3894 if ((c = memento_command_factory(n))) {
3898 } else if (n->name() == "NoteDiffCommand") {
3899 PBD::ID id (n->property("midi-source")->value());
3900 boost::shared_ptr<MidiSource> midi_source =
3901 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3903 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3905 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3908 } else if (n->name() == "SysExDiffCommand") {
3910 PBD::ID id (n->property("midi-source")->value());
3911 boost::shared_ptr<MidiSource> midi_source =
3912 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3914 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3916 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3919 } else if (n->name() == "PatchChangeDiffCommand") {
3921 PBD::ID id (n->property("midi-source")->value());
3922 boost::shared_ptr<MidiSource> midi_source =
3923 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3925 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3927 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3930 } else if (n->name() == "StatefulDiffCommand") {
3931 if ((c = stateful_diff_command_factory (n))) {
3932 ut->add_command (c);
3935 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3946 Session::config_changed (std::string p, bool ours)
3952 if (p == "auto-loop") {
3954 } else if (p == "session-monitoring") {
3956 } else if (p == "auto-input") {
3958 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3959 /* auto-input only makes a difference if we're rolling */
3960 set_track_monitor_input_status (!config.get_auto_input());
3963 } else if (p == "punch-in") {
3967 if ((location = _locations->auto_punch_location()) != 0) {
3969 if (config.get_punch_in ()) {
3970 auto_punch_start_changed (location);
3972 clear_events (SessionEvent::PunchIn);
3976 } else if (p == "punch-out") {
3980 if ((location = _locations->auto_punch_location()) != 0) {
3982 if (config.get_punch_out()) {
3983 auto_punch_end_changed (location);
3985 clear_events (SessionEvent::PunchOut);
3989 } else if (p == "edit-mode") {
3991 Glib::Threads::Mutex::Lock lm (playlists->lock);
3993 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3994 (*i)->set_edit_mode (Config->get_edit_mode ());
3997 } else if (p == "use-video-sync") {
3999 waiting_for_sync_offset = config.get_use_video_sync();
4001 } else if (p == "mmc-control") {
4003 //poke_midi_thread ();
4005 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4007 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4009 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4011 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4013 } else if (p == "midi-control") {
4015 //poke_midi_thread ();
4017 } else if (p == "raid-path") {
4019 setup_raid_path (config.get_raid_path());
4021 } else if (p == "timecode-format") {
4025 } else if (p == "video-pullup") {
4029 } else if (p == "seamless-loop") {
4031 if (play_loop && transport_rolling()) {
4032 // to reset diskstreams etc
4033 request_play_loop (true);
4036 } else if (p == "rf-speed") {
4038 cumulative_rf_motion = 0;
4041 } else if (p == "click-sound") {
4043 setup_click_sounds (1);
4045 } else if (p == "click-emphasis-sound") {
4047 setup_click_sounds (-1);
4049 } else if (p == "clicking") {
4051 if (Config->get_clicking()) {
4052 if (_click_io && click_data) { // don't require emphasis data
4059 } else if (p == "click-record-only") {
4061 _click_rec_only = Config->get_click_record_only();
4063 } else if (p == "click-gain") {
4066 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4069 } else if (p == "send-mtc") {
4071 if (Config->get_send_mtc ()) {
4072 /* mark us ready to send */
4073 next_quarter_frame_to_send = 0;
4076 } else if (p == "send-mmc") {
4078 _mmc->enable_send (Config->get_send_mmc ());
4079 if (Config->get_send_mmc ()) {
4080 /* re-initialize MMC */
4081 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4082 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4085 } else if (p == "jack-time-master") {
4087 engine().reset_timebase ();
4089 } else if (p == "native-file-header-format") {
4091 if (!first_file_header_format_reset) {
4092 reset_native_file_format ();
4095 first_file_header_format_reset = false;
4097 } else if (p == "native-file-data-format") {
4099 if (!first_file_data_format_reset) {
4100 reset_native_file_format ();
4103 first_file_data_format_reset = false;
4105 } else if (p == "external-sync") {
4106 if (!config.get_external_sync()) {
4107 drop_sync_source ();
4109 switch_to_sync_source (Config->get_sync_source());
4111 } else if (p == "denormal-model") {
4113 } else if (p == "history-depth") {
4114 set_history_depth (Config->get_history_depth());
4115 } else if (p == "remote-model") {
4116 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4119 } else if (p == "initial-program-change") {
4121 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4124 buf[0] = MIDI::program; // channel zero by default
4125 buf[1] = (Config->get_initial_program_change() & 0x7f);
4127 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4129 } else if (p == "solo-mute-override") {
4130 // catch_up_on_solo_mute_override ();
4131 } else if (p == "listen-position" || p == "pfl-position") {
4132 listen_position_changed ();
4133 } else if (p == "solo-control-is-listen-control") {
4134 solo_control_mode_changed ();
4135 } else if (p == "solo-mute-gain") {
4136 _solo_cut_control->Changed (true, Controllable::NoGroup);
4137 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4138 last_timecode_valid = false;
4139 } else if (p == "playback-buffer-seconds") {
4140 AudioSource::allocate_working_buffers (sample_rate());
4141 } else if (p == "ltc-source-port") {
4142 reconnect_ltc_input ();
4143 } else if (p == "ltc-sink-port") {
4144 reconnect_ltc_output ();
4145 } else if (p == "timecode-generator-offset") {
4146 ltc_tx_parse_offset();
4147 } else if (p == "auto-return-target-list") {
4148 follow_playhead_priority ();
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 = new XMLNode ("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 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5274 if (!afs || afs->readable_length () == 0) {
5277 if (only_used_sources) {
5281 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5285 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5288 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5289 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5290 if (!afs || afs->readable_length () == 0) {
5294 if (only_used_sources) {
5298 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5303 std::string from = afs->path();
5305 if (compress_audio != NO_ENCODE) {
5306 total_size += afs->readable_length ();
5308 /* copy files as-is */
5309 if (!afs->within_session()) {
5310 string to = Glib::path_get_basename (from);
5312 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5313 * - avoid conflict with files existing in interchange
5314 * - avoid conflict with other embedded sources
5316 if (audio_file_names.find (to) == audio_file_names.end ()) {
5317 // we need a new name, add a '-<num>' before the '.<ext>'
5318 string bn = to.substr (0, to.find_last_of ('.'));
5319 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5320 to = bn + "-1" + ext;
5322 while (audio_file_names.find (to) == audio_file_names.end ()) {
5323 to = bump_name_once (to, '-');
5326 audio_file_names.insert (to);
5327 filemap[from] = make_new_audio_path (to, name, name);
5329 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5331 orig_origin[afs] = afs->origin ();
5332 afs->set_origin ("");
5335 filemap[from] = make_new_media_path (from, name, name);
5342 if (compress_audio != NO_ENCODE) {
5344 progress->set_progress (2); // set to "encoding"
5345 progress->set_progress (0);
5348 Glib::Threads::Mutex::Lock lm (source_lock);
5349 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5350 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5351 if (!afs || afs->readable_length () == 0) {
5355 if (only_used_sources) {
5359 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5364 orig_sources[afs] = afs->path();
5365 orig_gain[afs] = afs->gain();
5367 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5369 std::string channelsuffix = "";
5370 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5371 /* embedded external multi-channel files are converted to multiple-mono */
5372 channelsuffix = string_compose ("-c%1", afs->channel ());
5374 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5375 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5377 /* avoid name collisions of external files with same name */
5378 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5379 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5381 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5382 new_path = bump_name_once (new_path, '-');
5386 progress->descend ((float)afs->readable_length () / total_size);
5390 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5391 afs->replace_file (new_path);
5392 afs->set_gain (ns->gain(), true);
5395 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5399 progress->ascend ();
5405 progress->set_progress (-1); // set to "archiving"
5406 progress->set_progress (0);
5409 /* index files relevant for this session */
5410 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5411 vector<string> files;
5413 size_t prefix_len = (*sd).path.size();
5414 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5418 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5420 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5421 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5422 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5424 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5425 std::string from = *i;
5428 string filename = Glib::path_get_basename (from);
5429 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5430 if (filename == ".DS_STORE") {
5435 if (from.find (audiofile_dir_string) != string::npos) {
5437 } else if (from.find (midifile_dir_string) != string::npos) {
5438 filemap[from] = make_new_media_path (from, name, name);
5439 } else if (from.find (videofile_dir_string) != string::npos) {
5440 filemap[from] = make_new_media_path (from, name, name);
5442 bool do_copy = true;
5443 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5444 if (from.find (*v) != string::npos) {
5449 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5450 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5457 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5463 /* write session file */
5465 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5467 save_state (name, false, false, false, true, only_used_sources);
5469 save_default_options ();
5471 size_t prefix_len = _path.size();
5472 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5476 /* collect session-state files */
5477 vector<string> files;
5478 do_not_copy_extensions.clear ();
5479 do_not_copy_extensions.push_back (history_suffix);
5481 blacklist_dirs.clear ();
5482 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5484 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5485 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5486 std::string from = *i;
5487 bool do_copy = true;
5488 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5489 if (from.find (*v) != string::npos) {
5494 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5495 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5501 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5505 /* restore original values */
5508 set_snapshot_name (old_snapshot);
5509 (*_session_dir) = old_sd;
5510 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5511 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5513 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5514 i->first->set_origin (i->second);
5516 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5517 i->first->replace_file (i->second);
5519 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5520 i->first->set_gain (i->second, true);
5523 int rv = ar.create (filemap, compression_level);
5524 remove_directory (to_dir);
5530 Session::undo (uint32_t n)
5532 if (actively_recording()) {
5540 Session::redo (uint32_t n)
5542 if (actively_recording()) {