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);
185 interpolation.add_channel ();
187 if (config.get_use_video_sync()) {
188 waiting_for_sync_offset = true;
190 waiting_for_sync_offset = false;
193 last_rr_session_dir = session_dirs.begin();
195 set_history_depth (Config->get_history_depth());
197 /* default: assume simple stereo speaker configuration */
199 _speakers->setup_default_speakers (2);
201 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
202 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
203 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
204 add_controllable (_solo_cut_control);
206 /* These are all static "per-class" signals */
208 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
209 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
210 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
211 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
212 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
214 /* stop IO objects from doing stuff until we're ready for them */
216 Delivery::disable_panners ();
217 IO::disable_connecting ();
221 Session::post_engine_init ()
223 BootMessage (_("Set block size and sample rate"));
225 set_block_size (_engine.samples_per_cycle());
226 set_sample_rate (_engine.sample_rate());
228 BootMessage (_("Using configuration"));
230 _midi_ports = new MidiPortManager;
232 MIDISceneChanger* msc;
234 _scene_changer = msc = new MIDISceneChanger (*this);
235 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
236 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
238 boost::function<samplecnt_t(void)> timer_func (boost::bind (&Session::audible_sample, this, (bool*)(0)));
239 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
241 setup_midi_machine_control ();
243 if (_butler->start_thread()) {
244 error << _("Butler did not start") << endmsg;
248 if (start_midi_thread ()) {
249 error << _("MIDI I/O thread did not start") << endmsg;
253 setup_click_sounds (0);
254 setup_midi_control ();
256 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
257 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
260 /* tempo map requires sample rate knowledge */
263 _tempo_map = new TempoMap (_current_sample_rate);
264 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
265 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
266 } catch (std::exception const & e) {
267 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
270 error << _("Unknown exception during session setup") << endmsg;
275 /* MidiClock requires a tempo map */
278 midi_clock = new MidiClockTicker ();
279 midi_clock->set_session (this);
281 /* crossfades require sample rate knowledge */
283 SndFileSource::setup_standard_crossfades (*this, sample_rate());
284 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
285 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
287 DiskReader::allocate_working_buffers();
288 refresh_disk_space ();
290 /* we're finally ready to call set_state() ... all objects have
291 * been created, the engine is running.
296 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
297 error << _("Could not set session state from XML") << endmsg;
300 } catch (PBD::unknown_enumeration& e) {
301 error << _("Session state: ") << e.what() << endmsg;
305 // set_state() will call setup_raid_path(), but if it's a new session we need
306 // to call setup_raid_path() here.
307 setup_raid_path (_path);
312 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
313 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
315 Config->map_parameters (ff);
316 config.map_parameters (ft);
317 _butler->map_parameters ();
319 /* Reset all panners */
321 Delivery::reset_panners ();
323 /* this will cause the CPM to instantiate any protocols that are in use
324 * (or mandatory), which will pass it this Session, and then call
325 * set_state() on each instantiated protocol to match stored state.
328 ControlProtocolManager::instance().set_session (this);
330 /* This must be done after the ControlProtocolManager set_session above,
331 as it will set states for ports which the ControlProtocolManager creates.
334 // XXX set state of MIDI::Port's
335 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
337 /* And this must be done after the MIDI::Manager::set_port_states as
338 * it will try to make connections whose details are loaded by set_port_states.
343 /* Let control protocols know that we are now all connected, so they
344 * could start talking to surfaces if they want to.
347 ControlProtocolManager::instance().midi_connectivity_established ();
349 if (_is_new && !no_auto_connect()) {
350 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
351 auto_connect_master_bus ();
354 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
356 /* update latencies */
358 initialize_latencies ();
360 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
361 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
362 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
364 } catch (AudioEngine::PortRegistrationFailure& err) {
365 error << err.what() << endmsg;
367 } catch (std::exception const & e) {
368 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
371 error << _("Unknown exception during session setup") << endmsg;
375 BootMessage (_("Reset Remote Controls"));
377 // send_full_time_code (0);
378 _engine.transport_locate (0);
380 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
381 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
383 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
386 /* initial program change will be delivered later; see ::config_changed() */
388 _state_of_the_state = Clean;
390 Port::set_connecting_blocked (false);
392 DirtyChanged (); /* EMIT SIGNAL */
396 } else if (state_was_pending) {
398 remove_pending_capture_state ();
399 state_was_pending = false;
402 /* Now, finally, we can fill the playback buffers */
404 BootMessage (_("Filling playback buffers"));
406 boost::shared_ptr<RouteList> rl = routes.reader();
407 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
408 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
409 if (trk && !trk->is_private_route()) {
410 trk->seek (_transport_sample, true);
418 Session::session_loaded ()
422 _state_of_the_state = Clean;
424 DirtyChanged (); /* EMIT SIGNAL */
428 } else if (state_was_pending) {
430 remove_pending_capture_state ();
431 state_was_pending = false;
434 /* Now, finally, we can fill the playback buffers */
436 BootMessage (_("Filling playback buffers"));
437 force_locate (_transport_sample, false);
441 Session::raid_path () const
443 Searchpath raid_search_path;
445 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
446 raid_search_path += (*i).path;
449 return raid_search_path.to_string ();
453 Session::setup_raid_path (string path)
462 session_dirs.clear ();
464 Searchpath search_path(path);
465 Searchpath sound_search_path;
466 Searchpath midi_search_path;
468 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
470 sp.blocks = 0; // not needed
471 session_dirs.push_back (sp);
473 SessionDirectory sdir(sp.path);
475 sound_search_path += sdir.sound_path ();
476 midi_search_path += sdir.midi_path ();
479 // reset the round-robin soundfile path thingie
480 last_rr_session_dir = session_dirs.begin();
484 Session::path_is_within_session (const std::string& path)
486 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
487 if (PBD::path_is_within (i->path, path)) {
495 Session::ensure_subdirs ()
499 dir = session_directory().peak_path();
501 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
502 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 dir = session_directory().sound_path();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = session_directory().midi_path();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
520 dir = session_directory().dead_path();
522 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
523 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
527 dir = session_directory().export_path();
529 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
534 dir = analysis_dir ();
536 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
537 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
541 dir = plugins_dir ();
543 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
544 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
548 dir = externals_dir ();
550 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
551 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
558 /** @param session_template directory containing session template, or empty.
559 * Caller must not hold process lock.
562 Session::create (const string& session_template, BusProfile* bus_profile)
564 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
565 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
569 if (ensure_subdirs ()) {
573 _writable = exists_and_writable (_path);
575 if (!session_template.empty()) {
576 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
578 FILE* in = g_fopen (in_path.c_str(), "rb");
581 /* no need to call legalize_for_path() since the string
582 * in session_template is already a legal path name
584 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
586 FILE* out = g_fopen (out_path.c_str(), "wb");
590 stringstream new_session;
593 size_t charsRead = fread (buf, sizeof(char), 1024, in);
596 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
601 if (charsRead == 0) {
604 new_session.write (buf, charsRead);
608 string file_contents = new_session.str();
609 size_t writeSize = file_contents.length();
610 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
611 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
619 if (!ARDOUR::Profile->get_trx()) {
620 /* Copy plugin state files from template to new session */
621 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
622 copy_recurse (template_plugins, plugins_dir ());
628 error << string_compose (_("Could not open %1 for writing session template"), out_path)
635 error << string_compose (_("Could not open session template %1 for reading"), in_path)
642 if (Profile->get_trx()) {
644 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
645 * Remember that this is a brand new session. Sessions
646 * loaded from saved state will get this range from the saved state.
649 set_session_range_location (0, 0);
651 /* Initial loop location, from absolute zero, length 10 seconds */
653 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
654 _locations->add (loc, true);
655 set_auto_loop_location (loc);
658 _state_of_the_state = Clean;
660 /* set up Master Out and Monitor Out if necessary */
664 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
665 if (bus_profile->master_out_channels) {
666 int rv = add_master_bus (count);
672 if (Config->get_use_monitor_bus())
673 add_monitor_section ();
681 Session::maybe_write_autosave()
683 if (dirty() && record_status() != Recording) {
684 save_state("", true);
689 Session::remove_pending_capture_state ()
691 std::string pending_state_file_path(_session_dir->root_path());
693 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
695 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
697 if (g_remove (pending_state_file_path.c_str()) != 0) {
698 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
699 pending_state_file_path, g_strerror (errno)) << endmsg;
703 /** Rename a state file.
704 * @param old_name Old snapshot name.
705 * @param new_name New snapshot name.
708 Session::rename_state (string old_name, string new_name)
710 if (old_name == _current_snapshot_name || old_name == _name) {
711 /* refuse to rename the current snapshot or the "main" one */
715 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
716 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
718 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
719 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
721 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
722 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
723 old_name, new_name, g_strerror(errno)) << endmsg;
727 /** Remove a state file.
728 * @param snapshot_name Snapshot name.
731 Session::remove_state (string snapshot_name)
733 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
734 // refuse to remove the current snapshot or the "main" one
738 std::string xml_path(_session_dir->root_path());
740 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
742 if (!create_backup_file (xml_path)) {
743 // don't remove it if a backup can't be made
744 // create_backup_file will log the error.
749 if (g_remove (xml_path.c_str()) != 0) {
750 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
751 xml_path, g_strerror (errno)) << endmsg;
755 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
757 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only, bool for_archive, bool only_used_assets)
759 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
762 std::string xml_path(_session_dir->root_path());
764 /* prevent concurrent saves from different threads */
766 Glib::Threads::Mutex::Lock lm (save_state_lock);
767 Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK);
772 if (!_writable || (_state_of_the_state & CannotSave)) {
776 if (g_atomic_int_get(&_suspend_save)) {
780 _save_queued = false;
782 snapshot_t fork_state = NormalSave;
783 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) {
784 /* snapshot, close midi */
785 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
789 const int64_t save_start_time = g_get_monotonic_time();
792 /* tell sources we're saving first, in case they write out to a new file
793 * which should be saved with the state rather than the old one */
794 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
796 i->second->session_saved();
797 } catch (Evoral::SMF::FileError& e) {
798 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
802 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, for_archive);
804 SessionSaveUnderway (); /* EMIT SIGNAL */
806 bool mark_as_clean = true;
807 if (!snapshot_name.empty() && !switch_to_snapshot) {
808 mark_as_clean = false;
812 mark_as_clean = false;
813 tree.set_root (&get_template());
815 tree.set_root (&state (false, fork_state, only_used_assets));
818 if (snapshot_name.empty()) {
819 snapshot_name = _current_snapshot_name;
820 } else if (switch_to_snapshot) {
821 set_snapshot_name (snapshot_name);
824 assert (!snapshot_name.empty());
828 /* proper save: use statefile_suffix (.ardour in English) */
830 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
832 /* make a backup copy of the old file */
834 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
835 // create_backup_file will log the error
841 /* pending save: use pending_suffix (.pending in English) */
842 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
845 std::string tmp_path(_session_dir->root_path());
846 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
849 cerr << "actually writing state to " << tmp_path << endl;
852 if (!tree.write (tmp_path)) {
853 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
854 if (g_remove (tmp_path.c_str()) != 0) {
855 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
856 tmp_path, g_strerror (errno)) << endmsg;
863 cerr << "renaming state to " << xml_path << endl;
866 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
867 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
868 tmp_path, xml_path, g_strerror(errno)) << endmsg;
869 if (g_remove (tmp_path.c_str()) != 0) {
870 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
871 tmp_path, g_strerror (errno)) << endmsg;
877 if (!pending && !for_archive) {
879 save_history (snapshot_name);
882 bool was_dirty = dirty();
884 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
887 DirtyChanged (); /* EMIT SIGNAL */
891 StateSaved (snapshot_name); /* EMIT SIGNAL */
895 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
896 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
902 Session::restore_state (string snapshot_name)
905 if (load_state (snapshot_name) == 0) {
906 set_state (*state_tree->root(), Stateful::loading_state_version);
910 // unknown_enumeration
918 Session::load_state (string snapshot_name)
923 state_was_pending = false;
925 /* check for leftover pending state from a crashed capture attempt */
927 std::string xmlpath(_session_dir->root_path());
928 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
930 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
932 /* there is pending state from a crashed capture attempt */
934 boost::optional<int> r = AskAboutPendingState();
935 if (r.get_value_or (1)) {
936 state_was_pending = true;
940 if (!state_was_pending) {
941 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
944 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
945 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
946 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
947 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
952 state_tree = new XMLTree;
956 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
958 if (!state_tree->read (xmlpath)) {
959 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
965 XMLNode const & root (*state_tree->root());
967 if (root.name() != X_("Session")) {
968 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
975 root.get_property ("version", version);
976 Stateful::loading_state_version = parse_stateful_loading_version (version);
978 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
979 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
980 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
983 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
985 std::string backup_path(_session_dir->root_path());
986 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
987 backup_path = Glib::build_filename (backup_path, backup_filename);
989 // only create a backup for a given statefile version once
991 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
993 VersionMismatch (xmlpath, backup_path);
995 if (!copy_file (xmlpath, backup_path)) {;
1001 save_snapshot_name (snapshot_name);
1007 Session::load_options (const XMLNode& node)
1009 config.set_variables (node);
1014 Session::save_default_options ()
1016 return config.save_state();
1020 Session::get_state ()
1022 /* this is not directly called, but required by PBD::Stateful */
1024 return state (false, NormalSave);
1028 Session::get_template ()
1030 /* if we don't disable rec-enable, diskstreams
1031 will believe they need to store their capture
1032 sources in their state node.
1035 disable_record (false);
1037 return state (true, NormalSave);
1040 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1041 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1044 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1046 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1049 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1053 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1056 XMLNode* node = new XMLNode("TrackState"); // XXX
1059 PlaylistSet playlists; // SessionPlaylists
1062 // these will work with new_route_from_template()
1063 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1064 child = node->add_child ("Routes");
1065 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1066 if ((*i)->is_auditioner()) {
1069 if ((*i)->is_master() || (*i)->is_monitor()) {
1072 child->add_child_nocopy ((*i)->get_state());
1073 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1075 playlists.insert (track->playlist ());
1079 // on load, Regions in the playlists need to resolve and map Source-IDs
1080 // also playlist needs to be merged or created with new-name..
1081 // ... and Diskstream in tracks adjusted to use the correct playlist
1082 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1083 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1084 child->add_child_nocopy ((*i)->get_state ());
1085 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1086 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1087 const Region::SourceList& sl = (*s)->sources ();
1088 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1089 sources.insert (*sli);
1094 child = node->add_child ("Sources");
1095 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1096 child->add_child_nocopy ((*i)->get_state ());
1097 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1099 #ifdef PLATFORM_WINDOWS
1102 string p = fs->path ();
1103 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1107 std::string sn = Glib::build_filename (path, "share.axml");
1110 tree.set_root (node);
1111 return tree.write (sn.c_str());
1115 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
1117 pl->deep_sources (*all_sources);
1122 struct route_id_compare {
1124 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1126 return r1->id () < r2->id ();
1132 Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets)
1135 XMLNode* node = new XMLNode("Session");
1138 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1140 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1142 child = node->add_child ("ProgramVersion");
1143 child->set_property("created-with", created_with);
1145 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1146 child->set_property("modified-with", modified_with);
1148 /* store configuration settings */
1150 if (!save_template) {
1152 node->set_property ("name", _name);
1153 node->set_property ("sample-rate", _base_sample_rate);
1155 if (session_dirs.size() > 1) {
1159 vector<space_and_path>::iterator i = session_dirs.begin();
1160 vector<space_and_path>::iterator next;
1162 ++i; /* skip the first one */
1166 while (i != session_dirs.end()) {
1170 if (next != session_dirs.end()) {
1171 p += G_SEARCHPATH_SEPARATOR;
1180 child = node->add_child ("Path");
1181 child->add_content (p);
1183 node->set_property ("end-is-free", _session_range_end_is_free);
1186 /* save the ID counter */
1188 node->set_property ("id-counter", ID::counter());
1190 node->set_property ("name-counter", name_id_counter ());
1192 /* save the event ID counter */
1194 node->set_property ("event-counter", Evoral::event_id_counter());
1196 /* save the VCA counter */
1198 node->set_property ("vca-counter", VCA::get_next_vca_number());
1200 /* various options */
1202 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1203 if (!midi_port_nodes.empty()) {
1204 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1205 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1206 midi_port_stuff->add_child_nocopy (**n);
1208 node->add_child_nocopy (*midi_port_stuff);
1211 XMLNode& cfgxml (config.get_variables ());
1212 if (save_template) {
1213 /* exclude search-paths from template */
1214 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1215 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1216 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1218 node->add_child_nocopy (cfgxml);
1220 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1222 child = node->add_child ("Sources");
1224 if (!save_template) {
1225 Glib::Threads::Mutex::Lock sl (source_lock);
1227 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1229 if (only_used_assets) {
1230 playlists->sync_all_regions_with_regions ();
1231 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1234 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1236 /* Don't save information about non-file Sources, or
1237 * about non-destructive file sources that are empty
1238 * and unused by any regions.
1240 boost::shared_ptr<FileSource> fs;
1242 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1246 if (!fs->destructive()) {
1247 if (fs->empty() && !fs->used()) {
1252 if (only_used_assets) {
1253 /* skip only unused audio files */
1254 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1255 if (afs && !afs->used()) {
1258 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1263 if (snapshot_type != NormalSave && fs->within_session ()) {
1264 /* copy MIDI sources to new file
1266 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1267 * because the GUI (midi_region) has a direct pointer to the midi-model
1268 * of the source, as does UndoTransaction.
1270 * On the upside, .mid files are not kept open. The file is only open
1271 * when reading the model initially and when flushing the model to disk:
1272 * source->session_saved () or export.
1274 * We can change the _path of the existing source under the hood, keeping
1275 * all IDs, references and pointers intact.
1277 boost::shared_ptr<SMFSource> ms;
1278 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1279 const std::string ancestor_name = ms->ancestor_name();
1280 const std::string base = PBD::basename_nosuffix(ancestor_name);
1281 const string path = new_midi_source_path (base, false);
1283 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1284 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1285 Source::Lock lm (ms->mutex());
1287 // TODO special-case empty, removable() files: just create a new removable.
1288 // (load + write flushes the model and creates the file)
1290 ms->load_model (lm);
1292 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1293 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1295 if (snapshot_type == SnapshotKeep) {
1296 /* keep working on current session.
1298 * Save snapshot-state with the original filename.
1299 * Switch to use new path for future saves of the main session.
1301 child->add_child_nocopy (ms->get_state());
1305 * ~SMFSource unlinks removable() files.
1307 std::string npath (ms->path ());
1308 ms->replace_file (newsrc->path ());
1309 newsrc->replace_file (npath);
1311 if (snapshot_type == SwitchToSnapshot) {
1312 /* save and switch to snapshot.
1314 * Leave the old file in place (as is).
1315 * Snapshot uses new source directly
1317 child->add_child_nocopy (ms->get_state());
1324 child->add_child_nocopy (siter->second->get_state());
1328 child = node->add_child ("Regions");
1330 if (!save_template) {
1331 Glib::Threads::Mutex::Lock rl (region_lock);
1333 if (!only_used_assets) {
1334 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1335 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1336 boost::shared_ptr<Region> r = i->second;
1337 /* only store regions not attached to playlists */
1338 if (r->playlist() == 0) {
1339 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1340 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1342 child->add_child_nocopy (r->get_state ());
1348 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1350 if (!cassocs.empty()) {
1351 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1353 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1354 if (i->first->playlist () == 0 && only_used_assets) {
1357 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1358 can->set_property (X_("copy"), i->first->id());
1359 can->set_property (X_("original"), i->second->id());
1360 ca->add_child_nocopy (*can);
1361 /* see above, child is still "Regions" here */
1362 if (i->second->playlist() == 0 && only_used_assets) {
1363 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1364 child->add_child_nocopy (ar->get_basic_state ());
1366 child->add_child_nocopy (ar->get_state ());
1373 if (!save_template) {
1375 node->add_child_nocopy (_selection->get_state());
1378 node->add_child_nocopy (_locations->get_state());
1381 Locations loc (*this);
1382 const bool was_dirty = dirty();
1383 // for a template, just create a new Locations, populate it
1384 // with the default start and end, and get the state for that.
1385 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1386 range->set (max_samplepos, 0);
1388 XMLNode& locations_state = loc.get_state();
1390 if (ARDOUR::Profile->get_trx() && _locations) {
1391 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1392 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1393 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1394 locations_state.add_child_nocopy ((*i)->get_state ());
1398 node->add_child_nocopy (locations_state);
1400 /* adding a location above will have marked the session
1401 * dirty. This is an artifact, so fix it if the session wasn't
1406 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1410 child = node->add_child ("Bundles");
1412 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1413 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1414 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1416 child->add_child_nocopy (b->get_state());
1421 node->add_child_nocopy (_vca_manager->get_state());
1423 child = node->add_child ("Routes");
1425 boost::shared_ptr<RouteList> r = routes.reader ();
1427 route_id_compare cmp;
1428 RouteList xml_node_order (*r);
1429 xml_node_order.sort (cmp);
1431 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1432 if (!(*i)->is_auditioner()) {
1433 if (save_template) {
1434 child->add_child_nocopy ((*i)->get_template());
1436 child->add_child_nocopy ((*i)->get_state());
1442 playlists->add_state (node, save_template, !only_used_assets);
1444 child = node->add_child ("RouteGroups");
1445 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1446 child->add_child_nocopy ((*i)->get_state());
1450 XMLNode* gain_child = node->add_child ("Click");
1451 gain_child->add_child_nocopy (_click_io->get_state ());
1452 gain_child->add_child_nocopy (_click_gain->get_state ());
1456 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1457 ltc_input_child->add_child_nocopy (_ltc_input->get_state ());
1461 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1462 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1465 node->add_child_nocopy (_speakers->get_state());
1466 node->add_child_nocopy (_tempo_map->get_state());
1467 node->add_child_nocopy (get_control_protocol_state());
1470 node->add_child_copy (*_extra_xml);
1474 Glib::Threads::Mutex::Lock lm (lua_lock);
1477 luabridge::LuaRef savedstate ((*_lua_save)());
1478 saved = savedstate.cast<std::string>();
1480 lua.collect_garbage ();
1483 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1484 std::string b64s (b64);
1487 XMLNode* script_node = new XMLNode (X_("Script"));
1488 script_node->set_property (X_("lua"), LUA_VERSION);
1489 script_node->add_content (b64s);
1490 node->add_child_nocopy (*script_node);
1497 Session::get_control_protocol_state ()
1499 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1500 return cpm.get_state();
1504 Session::set_state (const XMLNode& node, int version)
1511 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1513 if (node.name() != X_("Session")) {
1514 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1518 node.get_property ("name", _name);
1520 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1522 _nominal_sample_rate = _base_sample_rate;
1524 assert (AudioEngine::instance()->running ());
1525 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1526 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1527 if (r.get_value_or (0)) {
1533 created_with = "unknown";
1534 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1535 child->get_property (X_("created-with"), created_with);
1538 setup_raid_path(_session_dir->root_path());
1540 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1543 if (node.get_property (X_("id-counter"), counter)) {
1544 ID::init_counter (counter);
1546 /* old sessions used a timebased counter, so fake
1547 * the startup ID counter based on a standard
1552 ID::init_counter (now);
1555 if (node.get_property (X_("name-counter"), counter)) {
1556 init_name_id_counter (counter);
1559 if (node.get_property (X_("event-counter"), counter)) {
1560 Evoral::init_event_id_counter (counter);
1563 if (node.get_property (X_("vca-counter"), counter)) {
1564 VCA::set_next_vca_number (counter);
1566 VCA::set_next_vca_number (1);
1569 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1570 _midi_ports->set_midi_port_states (child->children());
1573 IO::disable_connecting ();
1575 Stateful::save_extra_xml (node);
1577 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1578 load_options (*child);
1579 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1580 load_options (*child);
1582 error << _("Session: XML state has no options section") << endmsg;
1585 if (version >= 3000) {
1586 if ((child = find_named_node (node, "Metadata")) == 0) {
1587 warning << _("Session: XML state has no metadata section") << endmsg;
1588 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1593 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1594 _speakers->set_state (*child, version);
1597 if ((child = find_named_node (node, "Sources")) == 0) {
1598 error << _("Session: XML state has no sources section") << endmsg;
1600 } else if (load_sources (*child)) {
1604 if ((child = find_named_node (node, "TempoMap")) == 0) {
1605 error << _("Session: XML state has no Tempo Map section") << endmsg;
1607 } else if (_tempo_map->set_state (*child, version)) {
1611 if ((child = find_named_node (node, "Locations")) == 0) {
1612 error << _("Session: XML state has no locations section") << endmsg;
1614 } else if (_locations->set_state (*child, version)) {
1618 locations_changed ();
1620 if (_session_range_location) {
1621 AudioFileSource::set_header_position_offset (_session_range_location->start());
1624 if ((child = find_named_node (node, "Regions")) == 0) {
1625 error << _("Session: XML state has no Regions section") << endmsg;
1627 } else if (load_regions (*child)) {
1631 if ((child = find_named_node (node, "Playlists")) == 0) {
1632 error << _("Session: XML state has no playlists section") << endmsg;
1634 } else if (playlists->load (*this, *child)) {
1638 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1640 } else if (playlists->load_unused (*this, *child)) {
1644 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1645 if (load_compounds (*child)) {
1650 if (version >= 3000) {
1651 if ((child = find_named_node (node, "Bundles")) == 0) {
1652 warning << _("Session: XML state has no bundles section") << endmsg;
1655 /* We can't load Bundles yet as they need to be able
1656 * to convert from port names to Port objects, which can't happen until
1658 _bundle_xml_node = new XMLNode (*child);
1662 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1663 _vca_manager->set_state (*child, version);
1666 if ((child = find_named_node (node, "Routes")) == 0) {
1667 error << _("Session: XML state has no routes section") << endmsg;
1669 } else if (load_routes (*child, version)) {
1673 /* Now that we have Routes and masters loaded, connect them if appropriate */
1675 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1677 if (version >= 3000) {
1679 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1680 error << _("Session: XML state has no route groups section") << endmsg;
1682 } else if (load_route_groups (*child, version)) {
1686 } else if (version < 3000) {
1688 if ((child = find_named_node (node, "EditGroups")) == 0) {
1689 error << _("Session: XML state has no edit groups section") << endmsg;
1691 } else if (load_route_groups (*child, version)) {
1695 if ((child = find_named_node (node, "MixGroups")) == 0) {
1696 error << _("Session: XML state has no mix groups section") << endmsg;
1698 } else if (load_route_groups (*child, version)) {
1703 if ((child = find_named_node (node, "Click")) == 0) {
1704 warning << _("Session: XML state has no click section") << endmsg;
1705 } else if (_click_io) {
1706 setup_click_state (&node);
1709 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1710 ControlProtocolManager::instance().set_state (*child, version);
1713 if ((child = find_named_node (node, "Script"))) {
1714 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1715 if (!(*n)->is_content ()) { continue; }
1717 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1719 Glib::Threads::Mutex::Lock lm (lua_lock);
1720 (*_lua_load)(std::string ((const char*)buf, size));
1721 } catch (luabridge::LuaException const& e) {
1722 cerr << "LuaException:" << e.what () << endl;
1728 if ((child = find_named_node (node, X_("Selection")))) {
1729 _selection->set_state (*child, version);
1732 update_route_record_state ();
1734 /* here beginneth the second phase ... */
1735 set_snapshot_name (_current_snapshot_name);
1737 StateReady (); /* EMIT SIGNAL */
1750 Session::load_routes (const XMLNode& node, int version)
1753 XMLNodeConstIterator niter;
1754 RouteList new_routes;
1756 nlist = node.children();
1760 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1762 boost::shared_ptr<Route> route;
1764 if (version < 3000) {
1765 route = XMLRouteFactory_2X (**niter, version);
1766 } else if (version < 5000) {
1767 route = XMLRouteFactory_3X (**niter, version);
1769 route = XMLRouteFactory (**niter, version);
1773 error << _("Session: cannot create Route from XML description.") << endmsg;
1777 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1779 new_routes.push_back (route);
1782 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1784 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1786 BootMessage (_("Finished adding tracks/busses"));
1791 boost::shared_ptr<Route>
1792 Session::XMLRouteFactory (const XMLNode& node, int version)
1794 boost::shared_ptr<Route> ret;
1796 if (node.name() != "Route") {
1800 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1803 pl_prop = node.property (X_("midi-playlist"));
1806 DataType type = DataType::AUDIO;
1807 node.get_property("default-type", type);
1809 assert (type != DataType::NIL);
1813 /* has at least 1 playlist, therefore a track ... */
1815 boost::shared_ptr<Track> track;
1817 if (type == DataType::AUDIO) {
1818 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1820 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1823 if (track->init()) {
1827 if (track->set_state (node, version)) {
1831 BOOST_MARK_TRACK (track);
1835 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1836 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1839 if (r->init () == 0 && r->set_state (node, version) == 0) {
1840 BOOST_MARK_ROUTE (r);
1848 boost::shared_ptr<Route>
1849 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1851 boost::shared_ptr<Route> ret;
1853 if (node.name() != "Route") {
1857 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1859 DataType type = DataType::AUDIO;
1860 node.get_property("default-type", type);
1862 assert (type != DataType::NIL);
1866 boost::shared_ptr<Track> track;
1868 if (type == DataType::AUDIO) {
1869 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1871 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1874 if (track->init()) {
1878 if (track->set_state (node, version)) {
1882 BOOST_MARK_TRACK (track);
1886 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1887 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1889 if (r->init () == 0 && r->set_state (node, version) == 0) {
1890 BOOST_MARK_ROUTE (r);
1898 boost::shared_ptr<Route>
1899 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1901 boost::shared_ptr<Route> ret;
1903 if (node.name() != "Route") {
1907 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1909 ds_prop = node.property (X_("diskstream"));
1912 DataType type = DataType::AUDIO;
1913 node.get_property("default-type", type);
1915 assert (type != DataType::NIL);
1919 /* see comment in current ::set_state() regarding diskstream
1920 * state and DiskReader/DiskWRiter.
1923 error << _("Could not find diskstream for route") << endmsg;
1924 return boost::shared_ptr<Route> ();
1926 boost::shared_ptr<Track> track;
1928 if (type == DataType::AUDIO) {
1929 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1931 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1934 if (track->init()) {
1938 if (track->set_state (node, version)) {
1942 BOOST_MARK_TRACK (track);
1946 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1947 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1949 if (r->init () == 0 && r->set_state (node, version) == 0) {
1950 BOOST_MARK_ROUTE (r);
1959 Session::load_regions (const XMLNode& node)
1962 XMLNodeConstIterator niter;
1963 boost::shared_ptr<Region> region;
1965 nlist = node.children();
1969 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1970 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1971 error << _("Session: cannot create Region from XML description.");
1972 XMLProperty const * name = (**niter).property("name");
1975 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1986 Session::load_compounds (const XMLNode& node)
1988 XMLNodeList calist = node.children();
1989 XMLNodeConstIterator caiter;
1990 XMLProperty const * caprop;
1992 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1993 XMLNode* ca = *caiter;
1997 if ((caprop = ca->property (X_("original"))) == 0) {
2000 orig_id = caprop->value();
2002 if ((caprop = ca->property (X_("copy"))) == 0) {
2005 copy_id = caprop->value();
2007 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2008 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2010 if (!orig || !copy) {
2011 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2017 RegionFactory::add_compound_association (orig, copy);
2024 Session::load_nested_sources (const XMLNode& node)
2027 XMLNodeConstIterator niter;
2029 nlist = node.children();
2031 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2032 if ((*niter)->name() == "Source") {
2034 /* it may already exist, so don't recreate it unnecessarily
2037 XMLProperty const * prop = (*niter)->property (X_("id"));
2039 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2043 ID source_id (prop->value());
2045 if (!source_by_id (source_id)) {
2048 SourceFactory::create (*this, **niter, true);
2050 catch (failed_constructor& err) {
2051 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2058 boost::shared_ptr<Region>
2059 Session::XMLRegionFactory (const XMLNode& node, bool full)
2061 XMLProperty const * type = node.property("type");
2065 const XMLNodeList& nlist = node.children();
2067 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2068 XMLNode *child = (*niter);
2069 if (child->name() == "NestedSource") {
2070 load_nested_sources (*child);
2074 if (!type || type->value() == "audio") {
2075 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2076 } else if (type->value() == "midi") {
2077 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2080 } catch (failed_constructor& err) {
2081 return boost::shared_ptr<Region> ();
2084 return boost::shared_ptr<Region> ();
2087 boost::shared_ptr<AudioRegion>
2088 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2090 XMLProperty const * prop;
2091 boost::shared_ptr<Source> source;
2092 boost::shared_ptr<AudioSource> as;
2094 SourceList master_sources;
2095 uint32_t nchans = 1;
2098 if (node.name() != X_("Region")) {
2099 return boost::shared_ptr<AudioRegion>();
2102 node.get_property (X_("channels"), nchans);
2104 if ((prop = node.property ("name")) == 0) {
2105 cerr << "no name for this region\n";
2109 if ((prop = node.property (X_("source-0"))) == 0) {
2110 if ((prop = node.property ("source")) == 0) {
2111 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2112 return boost::shared_ptr<AudioRegion>();
2116 PBD::ID s_id (prop->value());
2118 if ((source = source_by_id (s_id)) == 0) {
2119 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2120 return boost::shared_ptr<AudioRegion>();
2123 as = boost::dynamic_pointer_cast<AudioSource>(source);
2125 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2126 return boost::shared_ptr<AudioRegion>();
2129 sources.push_back (as);
2131 /* pickup other channels */
2133 for (uint32_t n=1; n < nchans; ++n) {
2134 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2135 if ((prop = node.property (buf)) != 0) {
2137 PBD::ID id2 (prop->value());
2139 if ((source = source_by_id (id2)) == 0) {
2140 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2141 return boost::shared_ptr<AudioRegion>();
2144 as = boost::dynamic_pointer_cast<AudioSource>(source);
2146 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2147 return boost::shared_ptr<AudioRegion>();
2149 sources.push_back (as);
2153 for (uint32_t n = 0; n < nchans; ++n) {
2154 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2155 if ((prop = node.property (buf)) != 0) {
2157 PBD::ID id2 (prop->value());
2159 if ((source = source_by_id (id2)) == 0) {
2160 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2161 return boost::shared_ptr<AudioRegion>();
2164 as = boost::dynamic_pointer_cast<AudioSource>(source);
2166 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2167 return boost::shared_ptr<AudioRegion>();
2169 master_sources.push_back (as);
2174 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2176 /* a final detail: this is the one and only place that we know how long missing files are */
2178 if (region->whole_file()) {
2179 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2180 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2182 sfp->set_length (region->length());
2187 if (!master_sources.empty()) {
2188 if (master_sources.size() != nchans) {
2189 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2191 region->set_master_sources (master_sources);
2199 catch (failed_constructor& err) {
2200 return boost::shared_ptr<AudioRegion>();
2204 boost::shared_ptr<MidiRegion>
2205 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2207 XMLProperty const * prop;
2208 boost::shared_ptr<Source> source;
2209 boost::shared_ptr<MidiSource> ms;
2212 if (node.name() != X_("Region")) {
2213 return boost::shared_ptr<MidiRegion>();
2216 if ((prop = node.property ("name")) == 0) {
2217 cerr << "no name for this region\n";
2221 if ((prop = node.property (X_("source-0"))) == 0) {
2222 if ((prop = node.property ("source")) == 0) {
2223 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2224 return boost::shared_ptr<MidiRegion>();
2228 PBD::ID s_id (prop->value());
2230 if ((source = source_by_id (s_id)) == 0) {
2231 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2232 return boost::shared_ptr<MidiRegion>();
2235 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2237 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2238 return boost::shared_ptr<MidiRegion>();
2241 sources.push_back (ms);
2244 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2245 /* a final detail: this is the one and only place that we know how long missing files are */
2247 if (region->whole_file()) {
2248 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2249 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2251 sfp->set_length (region->length());
2259 catch (failed_constructor& err) {
2260 return boost::shared_ptr<MidiRegion>();
2265 Session::get_sources_as_xml ()
2268 XMLNode* node = new XMLNode (X_("Sources"));
2269 Glib::Threads::Mutex::Lock lm (source_lock);
2271 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2272 node->add_child_nocopy (i->second->get_state());
2279 Session::reset_write_sources (bool mark_write_complete, bool force)
2281 boost::shared_ptr<RouteList> rl = routes.reader();
2282 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2283 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2285 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2286 tr->reset_write_sources(mark_write_complete, force);
2287 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2293 Session::load_sources (const XMLNode& node)
2296 XMLNodeConstIterator niter;
2297 /* don't need this but it stops some
2298 * versions of gcc complaining about
2299 * discarded return values.
2301 boost::shared_ptr<Source> source;
2303 nlist = node.children();
2306 std::map<std::string, std::string> relocation;
2308 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2309 #ifdef PLATFORM_WINDOWS
2313 XMLNode srcnode (**niter);
2314 bool try_replace_abspath = true;
2318 #ifdef PLATFORM_WINDOWS
2319 // do not show "insert media" popups (files embedded from removable media).
2320 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2322 if ((source = XMLSourceFactory (srcnode)) == 0) {
2323 error << _("Session: cannot create Source from XML description.") << endmsg;
2325 #ifdef PLATFORM_WINDOWS
2326 SetErrorMode(old_mode);
2329 } catch (MissingSource& err) {
2330 #ifdef PLATFORM_WINDOWS
2331 SetErrorMode(old_mode);
2334 /* try previous abs path replacements first */
2335 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2336 std::string dir = Glib::path_get_dirname (err.path);
2337 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2338 if (rl != relocation.end ()) {
2339 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2340 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2341 srcnode.set_property ("origin", newpath);
2342 try_replace_abspath = false;
2349 _missing_file_replacement = "";
2351 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2352 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2353 PROGRAM_NAME) << endmsg;
2357 if (!no_questions_about_missing_files) {
2358 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2363 switch (user_choice) {
2365 /* user added a new search location
2366 * or selected a new absolute path,
2368 if (Glib::path_is_absolute (err.path)) {
2369 if (!_missing_file_replacement.empty ()) {
2370 /* replace origin, in XML */
2371 std::string newpath = Glib::build_filename (
2372 _missing_file_replacement, Glib::path_get_basename (err.path));
2373 srcnode.set_property ("origin", newpath);
2374 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2375 _missing_file_replacement = "";
2382 /* user asked to quit the entire session load */
2386 no_questions_about_missing_files = true;
2390 no_questions_about_missing_files = true;
2397 case DataType::AUDIO:
2398 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2401 case DataType::MIDI:
2402 /* The MIDI file is actually missing so
2403 * just create a new one in the same
2404 * location. Do not announce its
2408 if (!Glib::path_is_absolute (err.path)) {
2409 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2411 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2416 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2417 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2418 /* reset ID to match the missing one */
2419 source->set_id (**niter);
2420 /* Now we can announce it */
2421 SourceFactory::SourceCreated (source);
2432 boost::shared_ptr<Source>
2433 Session::XMLSourceFactory (const XMLNode& node)
2435 if (node.name() != "Source") {
2436 return boost::shared_ptr<Source>();
2440 /* note: do peak building in another thread when loading session state */
2441 return SourceFactory::create (*this, node, true);
2444 catch (failed_constructor& err) {
2445 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2446 return boost::shared_ptr<Source>();
2451 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2453 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2457 bool absolute_path = Glib::path_is_absolute (template_name);
2459 /* directory to put the template in */
2460 std::string template_dir_path;
2462 if (!absolute_path) {
2463 std::string user_template_dir(user_template_directory());
2465 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2466 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2467 user_template_dir, g_strerror (errno)) << endmsg;
2471 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2473 template_dir_path = template_name;
2476 if (!ARDOUR::Profile->get_trx()) {
2477 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2478 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2479 template_dir_path) << endmsg;
2483 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2484 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2485 template_dir_path, g_strerror (errno)) << endmsg;
2491 std::string template_file_path;
2493 if (ARDOUR::Profile->get_trx()) {
2494 template_file_path = template_name;
2496 if (absolute_path) {
2497 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2499 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2503 SessionSaveUnderway (); /* EMIT SIGNAL */
2508 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2509 root = &get_template ();
2512 root->remove_nodes_and_delete (X_("description"));
2514 if (!description.empty()) {
2515 XMLNode* desc = new XMLNode (X_("description"));
2516 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2517 desc->add_child_nocopy (*desc_cont);
2519 root->add_child_nocopy (*desc);
2522 tree.set_root (root);
2524 if (!tree.write (template_file_path)) {
2525 error << _("template not saved") << endmsg;
2529 store_recent_templates (template_file_path);
2535 Session::refresh_disk_space ()
2537 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2539 Glib::Threads::Mutex::Lock lm (space_lock);
2541 /* get freespace on every FS that is part of the session path */
2543 _total_free_4k_blocks = 0;
2544 _total_free_4k_blocks_uncertain = false;
2546 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2547 #if defined(__NetBSD__)
2548 struct statvfs statfsbuf;
2550 statvfs (i->path.c_str(), &statfsbuf);
2552 struct statfs statfsbuf;
2554 statfs (i->path.c_str(), &statfsbuf);
2556 double const scale = statfsbuf.f_bsize / 4096.0;
2558 /* See if this filesystem is read-only */
2559 struct statvfs statvfsbuf;
2560 statvfs (i->path.c_str(), &statvfsbuf);
2562 /* f_bavail can be 0 if it is undefined for whatever
2563 filesystem we are looking at; Samba shares mounted
2564 via GVFS are an example of this.
2566 if (statfsbuf.f_bavail == 0) {
2567 /* block count unknown */
2569 i->blocks_unknown = true;
2570 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2571 /* read-only filesystem */
2573 i->blocks_unknown = false;
2575 /* read/write filesystem with known space */
2576 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2577 i->blocks_unknown = false;
2580 _total_free_4k_blocks += i->blocks;
2581 if (i->blocks_unknown) {
2582 _total_free_4k_blocks_uncertain = true;
2585 #elif defined PLATFORM_WINDOWS
2586 vector<string> scanned_volumes;
2587 vector<string>::iterator j;
2588 vector<space_and_path>::iterator i;
2589 DWORD nSectorsPerCluster, nBytesPerSector,
2590 nFreeClusters, nTotalClusters;
2594 _total_free_4k_blocks = 0;
2596 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2597 strncpy (disk_drive, (*i).path.c_str(), 3);
2601 volume_found = false;
2602 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2604 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2605 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2606 i->blocks = (uint32_t)(nFreeBytes / 4096);
2608 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2609 if (0 == j->compare(disk_drive)) {
2610 volume_found = true;
2615 if (!volume_found) {
2616 scanned_volumes.push_back(disk_drive);
2617 _total_free_4k_blocks += i->blocks;
2622 if (0 == _total_free_4k_blocks) {
2623 strncpy (disk_drive, path().c_str(), 3);
2626 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2628 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2629 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2630 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2637 Session::get_best_session_directory_for_new_audio ()
2639 vector<space_and_path>::iterator i;
2640 string result = _session_dir->root_path();
2642 /* handle common case without system calls */
2644 if (session_dirs.size() == 1) {
2648 /* OK, here's the algorithm we're following here:
2650 We want to select which directory to use for
2651 the next file source to be created. Ideally,
2652 we'd like to use a round-robin process so as to
2653 get maximum performance benefits from splitting
2654 the files across multiple disks.
2656 However, in situations without much diskspace, an
2657 RR approach may end up filling up a filesystem
2658 with new files while others still have space.
2659 Its therefore important to pay some attention to
2660 the freespace in the filesystem holding each
2661 directory as well. However, if we did that by
2662 itself, we'd keep creating new files in the file
2663 system with the most space until it was as full
2664 as all others, thus negating any performance
2665 benefits of this RAID-1 like approach.
2667 So, we use a user-configurable space threshold. If
2668 there are at least 2 filesystems with more than this
2669 much space available, we use RR selection between them.
2670 If not, then we pick the filesystem with the most space.
2672 This gets a good balance between the two
2676 refresh_disk_space ();
2678 int free_enough = 0;
2680 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2681 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2686 if (free_enough >= 2) {
2687 /* use RR selection process, ensuring that the one
2691 i = last_rr_session_dir;
2694 if (++i == session_dirs.end()) {
2695 i = session_dirs.begin();
2698 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2699 SessionDirectory sdir(i->path);
2700 if (sdir.create ()) {
2702 last_rr_session_dir = i;
2707 } while (i != last_rr_session_dir);
2711 /* pick FS with the most freespace (and that
2712 seems to actually work ...)
2715 vector<space_and_path> sorted;
2716 space_and_path_ascending_cmp cmp;
2718 sorted = session_dirs;
2719 sort (sorted.begin(), sorted.end(), cmp);
2721 for (i = sorted.begin(); i != sorted.end(); ++i) {
2722 SessionDirectory sdir(i->path);
2723 if (sdir.create ()) {
2725 last_rr_session_dir = i;
2735 Session::automation_dir () const
2737 return Glib::build_filename (_path, automation_dir_name);
2741 Session::analysis_dir () const
2743 return Glib::build_filename (_path, analysis_dir_name);
2747 Session::plugins_dir () const
2749 return Glib::build_filename (_path, plugins_dir_name);
2753 Session::externals_dir () const
2755 return Glib::build_filename (_path, externals_dir_name);
2759 Session::load_bundles (XMLNode const & node)
2761 XMLNodeList nlist = node.children();
2762 XMLNodeConstIterator niter;
2766 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2767 if ((*niter)->name() == "InputBundle") {
2768 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2769 } else if ((*niter)->name() == "OutputBundle") {
2770 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2772 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2781 Session::load_route_groups (const XMLNode& node, int version)
2783 XMLNodeList nlist = node.children();
2784 XMLNodeConstIterator niter;
2788 if (version >= 3000) {
2790 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2791 if ((*niter)->name() == "RouteGroup") {
2792 RouteGroup* rg = new RouteGroup (*this, "");
2793 add_route_group (rg);
2794 rg->set_state (**niter, version);
2798 } else if (version < 3000) {
2800 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2801 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2802 RouteGroup* rg = new RouteGroup (*this, "");
2803 add_route_group (rg);
2804 rg->set_state (**niter, version);
2813 state_file_filter (const string &str, void* /*arg*/)
2815 return (str.length() > strlen(statefile_suffix) &&
2816 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2820 remove_end(string state)
2822 string statename(state);
2824 string::size_type start,end;
2825 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2826 statename = statename.substr (start+1);
2829 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2830 end = statename.length();
2833 return string(statename.substr (0, end));
2837 Session::possible_states (string path)
2839 vector<string> states;
2840 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2842 transform(states.begin(), states.end(), states.begin(), remove_end);
2844 sort (states.begin(), states.end());
2850 Session::possible_states () const
2852 return possible_states(_path);
2856 Session::new_route_group (const std::string& name)
2858 RouteGroup* rg = NULL;
2860 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2861 if ((*i)->name () == name) {
2868 rg = new RouteGroup (*this, name);
2869 add_route_group (rg);
2875 Session::add_route_group (RouteGroup* g)
2877 _route_groups.push_back (g);
2878 route_group_added (g); /* EMIT SIGNAL */
2880 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2881 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2882 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2888 Session::remove_route_group (RouteGroup& rg)
2890 list<RouteGroup*>::iterator i;
2892 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2893 _route_groups.erase (i);
2896 route_group_removed (); /* EMIT SIGNAL */
2900 /** Set a new order for our route groups, without adding or removing any.
2901 * @param groups Route group list in the new order.
2904 Session::reorder_route_groups (list<RouteGroup*> groups)
2906 _route_groups = groups;
2908 route_groups_reordered (); /* EMIT SIGNAL */
2914 Session::route_group_by_name (string name)
2916 list<RouteGroup *>::iterator i;
2918 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2919 if ((*i)->name() == name) {
2927 Session::all_route_group() const
2929 return *_all_route_group;
2933 Session::add_commands (vector<Command*> const & cmds)
2935 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2941 Session::add_command (Command* const cmd)
2943 assert (_current_trans);
2944 DEBUG_UNDO_HISTORY (
2945 string_compose ("Current Undo Transaction %1, adding command: %2",
2946 _current_trans->name (),
2948 _current_trans->add_command (cmd);
2951 PBD::StatefulDiffCommand*
2952 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2954 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2960 Session::begin_reversible_command (const string& name)
2962 begin_reversible_command (g_quark_from_string (name.c_str ()));
2965 /** Begin a reversible command using a GQuark to identify it.
2966 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2967 * but there must be as many begin...()s as there are commit...()s.
2970 Session::begin_reversible_command (GQuark q)
2972 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2973 to hold all the commands that are committed. This keeps the order of
2974 commands correct in the history.
2977 if (_current_trans == 0) {
2978 DEBUG_UNDO_HISTORY (string_compose (
2979 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2981 /* start a new transaction */
2982 assert (_current_trans_quarks.empty ());
2983 _current_trans = new UndoTransaction();
2984 _current_trans->set_name (g_quark_to_string (q));
2986 DEBUG_UNDO_HISTORY (
2987 string_compose ("Begin Reversible Command, current transaction: %1",
2988 _current_trans->name ()));
2991 _current_trans_quarks.push_front (q);
2995 Session::abort_reversible_command ()
2997 if (_current_trans != 0) {
2998 DEBUG_UNDO_HISTORY (
2999 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
3000 _current_trans->clear();
3001 delete _current_trans;
3003 _current_trans_quarks.clear();
3008 Session::commit_reversible_command (Command *cmd)
3010 assert (_current_trans);
3011 assert (!_current_trans_quarks.empty ());
3016 DEBUG_UNDO_HISTORY (
3017 string_compose ("Current Undo Transaction %1, adding command: %2",
3018 _current_trans->name (),
3020 _current_trans->add_command (cmd);
3023 DEBUG_UNDO_HISTORY (
3024 string_compose ("Commit Reversible Command, current transaction: %1",
3025 _current_trans->name ()));
3027 _current_trans_quarks.pop_front ();
3029 if (!_current_trans_quarks.empty ()) {
3030 DEBUG_UNDO_HISTORY (
3031 string_compose ("Commit Reversible Command, transaction is not "
3032 "top-level, current transaction: %1",
3033 _current_trans->name ()));
3034 /* the transaction we're committing is not the top-level one */
3038 if (_current_trans->empty()) {
3039 /* no commands were added to the transaction, so just get rid of it */
3040 DEBUG_UNDO_HISTORY (
3041 string_compose ("Commit Reversible Command, No commands were "
3042 "added to current transaction: %1",
3043 _current_trans->name ()));
3044 delete _current_trans;
3049 gettimeofday (&now, 0);
3050 _current_trans->set_timestamp (now);
3052 _history.add (_current_trans);
3057 accept_all_audio_files (const string& path, void* /*arg*/)
3059 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3063 if (!AudioFileSource::safe_audio_file_extension (path)) {
3071 accept_all_midi_files (const string& path, void* /*arg*/)
3073 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3077 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3078 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3079 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3083 accept_all_state_files (const string& path, void* /*arg*/)
3085 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3089 std::string const statefile_ext (statefile_suffix);
3090 if (path.length() >= statefile_ext.length()) {
3091 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3098 Session::find_all_sources (string path, set<string>& result)
3103 if (!tree.read (path)) {
3107 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3112 XMLNodeConstIterator niter;
3114 nlist = node->children();
3118 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3120 XMLProperty const * prop;
3122 if ((prop = (*niter)->property (X_("type"))) == 0) {
3126 DataType type (prop->value());
3128 if ((prop = (*niter)->property (X_("name"))) == 0) {
3132 if (Glib::path_is_absolute (prop->value())) {
3133 /* external file, ignore */
3141 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3142 result.insert (found_path);
3150 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3152 vector<string> state_files;
3154 string this_snapshot_path;
3160 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3161 ripped = ripped.substr (0, ripped.length() - 1);
3164 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3166 if (state_files.empty()) {
3171 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3172 this_snapshot_path += statefile_suffix;
3174 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3176 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3178 if (exclude_this_snapshot && *i == this_snapshot_path) {
3179 cerr << "\texcluded\n";
3184 if (find_all_sources (*i, result) < 0) {
3192 struct RegionCounter {
3193 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3194 AudioSourceList::iterator iter;
3195 boost::shared_ptr<Region> region;
3198 RegionCounter() : count (0) {}
3202 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3204 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3205 return r.get_value_or (1);
3209 Session::cleanup_regions ()
3211 bool removed = false;
3212 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3214 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3216 uint32_t used = playlists->region_use_count (i->second);
3218 if (used == 0 && !i->second->automatic ()) {
3219 boost::weak_ptr<Region> w = i->second;
3222 RegionFactory::map_remove (w);
3229 // re-check to remove parent references of compound regions
3230 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3231 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3235 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3236 if (0 == playlists->region_use_count (i->second)) {
3237 boost::weak_ptr<Region> w = i->second;
3239 RegionFactory::map_remove (w);
3246 /* dump the history list */
3253 Session::can_cleanup_peakfiles () const
3255 if (deletion_in_progress()) {
3258 if (!_writable || (_state_of_the_state & CannotSave)) {
3259 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3262 if (record_status() == Recording) {
3263 error << _("Cannot cleanup peak-files while recording") << endmsg;
3270 Session::cleanup_peakfiles ()
3272 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3277 assert (can_cleanup_peakfiles ());
3278 assert (!peaks_cleanup_in_progres());
3280 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3282 int timeout = 5000; // 5 seconds
3283 while (!SourceFactory::files_with_peaks.empty()) {
3284 Glib::usleep (1000);
3285 if (--timeout < 0) {
3286 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3287 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3292 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3293 boost::shared_ptr<AudioSource> as;
3294 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3295 as->close_peakfile();
3299 PBD::clear_directory (session_directory().peak_path());
3301 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3303 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3304 boost::shared_ptr<AudioSource> as;
3305 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3306 SourceFactory::setup_peakfile(as, true);
3313 Session::cleanup_sources (CleanupReport& rep)
3315 // FIXME: needs adaptation to midi
3317 vector<boost::shared_ptr<Source> > dead_sources;
3320 vector<string> candidates;
3321 vector<string> unused;
3322 set<string> sources_used_by_all_snapshots;
3329 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3331 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3333 /* this is mostly for windows which doesn't allow file
3334 * renaming if the file is in use. But we don't special
3335 * case it because we need to know if this causes
3336 * problems, and the easiest way to notice that is to
3337 * keep it in place for all platforms.
3340 request_stop (false);
3342 _butler->wait_until_finished ();
3344 /* consider deleting all unused playlists */
3346 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3351 /* sync the "all regions" property of each playlist with its current state */
3353 playlists->sync_all_regions_with_regions ();
3355 /* find all un-used sources */
3360 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3362 SourceMap::iterator tmp;
3367 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3371 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3372 dead_sources.push_back (i->second);
3373 i->second->drop_references ();
3379 /* build a list of all the possible audio directories for the session */
3381 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3382 SessionDirectory sdir ((*i).path);
3383 asp += sdir.sound_path();
3385 audio_path += asp.to_string();
3388 /* build a list of all the possible midi directories for the session */
3390 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3391 SessionDirectory sdir ((*i).path);
3392 msp += sdir.midi_path();
3394 midi_path += msp.to_string();
3396 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3397 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3399 /* add sources from all other snapshots as "used", but don't use this
3400 snapshot because the state file on disk still references sources we
3401 may have already dropped.
3404 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3406 /* Although the region factory has a list of all regions ever created
3407 * for this session, we're only interested in regions actually in
3408 * playlists right now. So merge all playlist regions lists together.
3410 * This will include the playlists used within compound regions.
3413 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3415 /* add our current source list
3418 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3419 boost::shared_ptr<FileSource> fs;
3420 SourceMap::iterator tmp = i;
3423 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3429 /* this is mostly for windows which doesn't allow file
3430 * renaming if the file is in use. But we do not special
3431 * case it because we need to know if this causes
3432 * problems, and the easiest way to notice that is to
3433 * keep it in place for all platforms.
3438 if (!fs->is_stub()) {
3440 /* Note that we're checking a list of all
3441 * sources across all snapshots with the list
3442 * of sources used by this snapshot.
3445 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3446 /* this source is in use by this snapshot */
3447 sources_used_by_all_snapshots.insert (fs->path());
3448 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3450 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3451 /* this source is NOT in use by this snapshot */
3453 /* remove all related regions from RegionFactory master list */
3455 RegionFactory::remove_regions_using_source (i->second);
3457 /* remove from our current source list
3458 * also. We may not remove it from
3459 * disk, because it may be used by
3460 * other snapshots, but it isn't used inside this
3461 * snapshot anymore, so we don't need a
3472 /* now check each candidate source to see if it exists in the list of
3473 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3476 cerr << "Candidates: " << candidates.size() << endl;
3477 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3479 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3484 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3486 tmppath1 = canonical_path (spath);
3487 tmppath2 = canonical_path ((*i));
3489 cerr << "\t => " << tmppath2 << endl;
3491 if (tmppath1 == tmppath2) {
3498 unused.push_back (spath);
3502 cerr << "Actually unused: " << unused.size() << endl;
3504 if (unused.empty()) {
3510 /* now try to move all unused files into the "dead" directory(ies) */
3512 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3517 /* don't move the file across filesystems, just
3518 * stick it in the `dead_dir_name' directory
3519 * on whichever filesystem it was already on.
3522 if ((*x).find ("/sounds/") != string::npos) {
3524 /* old school, go up 1 level */
3526 newpath = Glib::path_get_dirname (*x); // "sounds"
3527 newpath = Glib::path_get_dirname (newpath); // "session-name"
3531 /* new school, go up 4 levels */
3533 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3534 newpath = Glib::path_get_dirname (newpath); // "session-name"
3535 newpath = Glib::path_get_dirname (newpath); // "interchange"
3536 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3539 newpath = Glib::build_filename (newpath, dead_dir_name);
3541 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3542 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3546 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3548 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3550 /* the new path already exists, try versioning */
3552 char buf[PATH_MAX+1];
3556 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3559 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3560 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3564 if (version == 999) {
3565 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3569 newpath = newpath_v;
3574 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3575 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3576 newpath, g_strerror (errno)) << endmsg;
3580 /* see if there an easy to find peakfile for this file, and remove it. */
3582 string base = Glib::path_get_basename (*x);
3583 base += "%A"; /* this is what we add for the channel suffix of all native files,
3584 * or for the first channel of embedded files. it will miss
3585 * some peakfiles for other channels
3587 string peakpath = construct_peak_filepath (base);
3589 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3590 if (::g_unlink (peakpath.c_str ()) != 0) {
3591 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3592 g_strerror (errno)) << endmsg;
3593 /* try to back out */
3594 ::g_rename (newpath.c_str (), _path.c_str ());
3599 rep.paths.push_back (*x);
3600 rep.space += statbuf.st_size;
3603 /* dump the history list */
3607 /* save state so we don't end up a session file
3608 * referring to non-existent sources.
3615 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3621 Session::cleanup_trash_sources (CleanupReport& rep)
3623 // FIXME: needs adaptation for MIDI
3625 vector<space_and_path>::iterator i;
3631 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3633 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3635 clear_directory (dead_dir, &rep.space, &rep.paths);
3642 Session::set_dirty ()
3644 /* return early if there's nothing to do */
3649 /* never mark session dirty during loading */
3650 if (_state_of_the_state & Loading) {
3654 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3655 DirtyChanged(); /* EMIT SIGNAL */
3659 Session::set_clean ()
3661 bool was_dirty = dirty();
3663 _state_of_the_state = Clean;
3666 DirtyChanged(); /* EMIT SIGNAL */
3671 Session::set_deletion_in_progress ()
3673 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3677 Session::clear_deletion_in_progress ()
3679 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3683 Session::add_controllable (boost::shared_ptr<Controllable> c)
3685 /* this adds a controllable to the list managed by the Session.
3686 this is a subset of those managed by the Controllable class
3687 itself, and represents the only ones whose state will be saved
3688 as part of the session.
3691 Glib::Threads::Mutex::Lock lm (controllables_lock);
3692 controllables.insert (c);
3695 struct null_deleter { void operator()(void const *) const {} };
3698 Session::remove_controllable (Controllable* c)
3700 if (_state_of_the_state & Deletion) {
3704 Glib::Threads::Mutex::Lock lm (controllables_lock);
3706 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3708 if (x != controllables.end()) {
3709 controllables.erase (x);
3713 boost::shared_ptr<Controllable>
3714 Session::controllable_by_id (const PBD::ID& id)
3716 Glib::Threads::Mutex::Lock lm (controllables_lock);
3718 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3719 if ((*i)->id() == id) {
3724 return boost::shared_ptr<Controllable>();
3727 boost::shared_ptr<AutomationControl>
3728 Session::automation_control_by_id (const PBD::ID& id)
3730 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3734 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3737 Stateful::add_instant_xml (node, _path);
3740 if (write_to_config) {
3741 Config->add_instant_xml (node);
3746 Session::instant_xml (const string& node_name)
3748 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3749 if (get_disable_all_loaded_plugins ()) {
3753 return Stateful::instant_xml (node_name, _path);
3757 Session::save_history (string snapshot_name)
3765 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3766 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3770 if (snapshot_name.empty()) {
3771 snapshot_name = _current_snapshot_name;
3774 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3775 const string backup_filename = history_filename + backup_suffix;
3776 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3777 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3779 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3780 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3781 error << _("could not backup old history file, current history not saved") << endmsg;
3786 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3788 if (!tree.write (xml_path))
3790 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3792 if (g_remove (xml_path.c_str()) != 0) {
3793 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3794 xml_path, g_strerror (errno)) << endmsg;
3796 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3797 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3798 backup_path, g_strerror (errno)) << endmsg;
3808 Session::restore_history (string snapshot_name)
3812 if (snapshot_name.empty()) {
3813 snapshot_name = _current_snapshot_name;
3816 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3817 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3819 info << "Loading history from " << xml_path << endmsg;
3821 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3822 info << string_compose (_("%1: no history file \"%2\" for this session."),
3823 _name, xml_path) << endmsg;
3827 if (!tree.read (xml_path)) {
3828 error << string_compose (_("Could not understand session history file \"%1\""),
3829 xml_path) << endmsg;
3836 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3844 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3845 !t->get_property ("tv-usec", tv_usec)) {
3849 UndoTransaction* ut = new UndoTransaction ();
3850 ut->set_name (name);
3854 tv.tv_usec = tv_usec;
3855 ut->set_timestamp(tv);
3857 for (XMLNodeConstIterator child_it = t->children().begin();
3858 child_it != t->children().end(); child_it++)
3860 XMLNode *n = *child_it;
3863 if (n->name() == "MementoCommand" ||
3864 n->name() == "MementoUndoCommand" ||
3865 n->name() == "MementoRedoCommand") {
3867 if ((c = memento_command_factory(n))) {
3871 } else if (n->name() == "NoteDiffCommand") {
3872 PBD::ID id (n->property("midi-source")->value());
3873 boost::shared_ptr<MidiSource> midi_source =
3874 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3876 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3878 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3881 } else if (n->name() == "SysExDiffCommand") {
3883 PBD::ID id (n->property("midi-source")->value());
3884 boost::shared_ptr<MidiSource> midi_source =
3885 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3887 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3889 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3892 } else if (n->name() == "PatchChangeDiffCommand") {
3894 PBD::ID id (n->property("midi-source")->value());
3895 boost::shared_ptr<MidiSource> midi_source =
3896 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3898 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3900 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3903 } else if (n->name() == "StatefulDiffCommand") {
3904 if ((c = stateful_diff_command_factory (n))) {
3905 ut->add_command (c);
3908 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3919 Session::config_changed (std::string p, bool ours)
3925 if (p == "auto-loop") {
3927 } else if (p == "session-monitoring") {
3929 } else if (p == "auto-input") {
3931 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3932 /* auto-input only makes a difference if we're rolling */
3933 set_track_monitor_input_status (!config.get_auto_input());
3936 } else if (p == "punch-in") {
3940 if ((location = _locations->auto_punch_location()) != 0) {
3942 if (config.get_punch_in ()) {
3943 auto_punch_start_changed (location);
3945 clear_events (SessionEvent::PunchIn);
3949 } else if (p == "punch-out") {
3953 if ((location = _locations->auto_punch_location()) != 0) {
3955 if (config.get_punch_out()) {
3956 auto_punch_end_changed (location);
3958 clear_events (SessionEvent::PunchOut);
3962 } else if (p == "edit-mode") {
3964 Glib::Threads::Mutex::Lock lm (playlists->lock);
3966 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3967 (*i)->set_edit_mode (Config->get_edit_mode ());
3970 } else if (p == "use-video-sync") {
3972 waiting_for_sync_offset = config.get_use_video_sync();
3974 } else if (p == "mmc-control") {
3976 //poke_midi_thread ();
3978 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3980 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3982 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3984 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3986 } else if (p == "midi-control") {
3988 //poke_midi_thread ();
3990 } else if (p == "raid-path") {
3992 setup_raid_path (config.get_raid_path());
3994 } else if (p == "timecode-format") {
3998 } else if (p == "video-pullup") {
4002 } else if (p == "seamless-loop") {
4004 if (play_loop && transport_rolling()) {
4005 // to reset diskstreams etc
4006 request_play_loop (true);
4009 } else if (p == "rf-speed") {
4011 cumulative_rf_motion = 0;
4014 } else if (p == "click-sound") {
4016 setup_click_sounds (1);
4018 } else if (p == "click-emphasis-sound") {
4020 setup_click_sounds (-1);
4022 } else if (p == "clicking") {
4024 if (Config->get_clicking()) {
4025 if (_click_io && click_data) { // don't require emphasis data
4032 } else if (p == "click-record-only") {
4034 _click_rec_only = Config->get_click_record_only();
4036 } else if (p == "click-gain") {
4039 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4042 } else if (p == "send-mtc") {
4044 if (Config->get_send_mtc ()) {
4045 /* mark us ready to send */
4046 next_quarter_frame_to_send = 0;
4049 } else if (p == "send-mmc") {
4051 _mmc->enable_send (Config->get_send_mmc ());
4052 if (Config->get_send_mmc ()) {
4053 /* re-initialize MMC */
4054 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4055 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4058 } else if (p == "jack-time-master") {
4060 engine().reset_timebase ();
4062 } else if (p == "native-file-header-format") {
4064 if (!first_file_header_format_reset) {
4065 reset_native_file_format ();
4068 first_file_header_format_reset = false;
4070 } else if (p == "native-file-data-format") {
4072 if (!first_file_data_format_reset) {
4073 reset_native_file_format ();
4076 first_file_data_format_reset = false;
4078 } else if (p == "external-sync") {
4079 if (!config.get_external_sync()) {
4080 drop_sync_source ();
4082 switch_to_sync_source (Config->get_sync_source());
4084 } else if (p == "denormal-model") {
4086 } else if (p == "history-depth") {
4087 set_history_depth (Config->get_history_depth());
4088 } else if (p == "remote-model") {
4089 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4092 } else if (p == "initial-program-change") {
4094 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4097 buf[0] = MIDI::program; // channel zero by default
4098 buf[1] = (Config->get_initial_program_change() & 0x7f);
4100 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4102 } else if (p == "solo-mute-override") {
4103 // catch_up_on_solo_mute_override ();
4104 } else if (p == "listen-position" || p == "pfl-position") {
4105 listen_position_changed ();
4106 } else if (p == "solo-control-is-listen-control") {
4107 solo_control_mode_changed ();
4108 } else if (p == "solo-mute-gain") {
4109 _solo_cut_control->Changed (true, Controllable::NoGroup);
4110 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4111 last_timecode_valid = false;
4112 } else if (p == "playback-buffer-seconds") {
4113 AudioSource::allocate_working_buffers (sample_rate());
4114 } else if (p == "ltc-source-port") {
4115 reconnect_ltc_input ();
4116 } else if (p == "ltc-sink-port") {
4117 reconnect_ltc_output ();
4118 } else if (p == "timecode-generator-offset") {
4119 ltc_tx_parse_offset();
4120 } else if (p == "auto-return-target-list") {
4121 follow_playhead_priority ();
4128 Session::set_history_depth (uint32_t d)
4130 _history.set_depth (d);
4133 /** Connect things to the MMC object */
4135 Session::setup_midi_machine_control ()
4137 _mmc = new MIDI::MachineControl;
4139 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4140 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4142 if (!async_out || !async_out) {
4146 /* XXXX argh, passing raw pointers back into libmidi++ */
4148 MIDI::Port* mmc_in = async_in.get();
4149 MIDI::Port* mmc_out = async_out.get();
4151 _mmc->set_ports (mmc_in, mmc_out);
4153 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4154 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4155 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4156 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4157 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4158 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4159 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4160 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4161 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4162 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4163 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4164 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4165 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4167 /* also handle MIDI SPP because its so common */
4169 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4170 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4171 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4174 boost::shared_ptr<Controllable>
4175 Session::solo_cut_control() const
4177 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4178 * controls in Ardour that currently get presented to the user in the GUI that require
4179 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4181 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4182 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4185 return _solo_cut_control;
4189 Session::save_snapshot_name (const std::string & n)
4191 /* assure Stateful::_instant_xml is loaded
4192 * add_instant_xml() only adds to existing data and defaults
4193 * to use an empty Tree otherwise
4195 instant_xml ("LastUsedSnapshot");
4197 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4198 last_used_snapshot->set_property ("name", n);
4199 add_instant_xml (*last_used_snapshot, false);
4203 Session::set_snapshot_name (const std::string & n)
4205 _current_snapshot_name = n;
4206 save_snapshot_name (n);
4210 Session::rename (const std::string& new_name)
4212 string legal_name = legalize_for_path (new_name);
4218 string const old_sources_root = _session_dir->sources_root();
4220 if (!_writable || (_state_of_the_state & CannotSave)) {
4221 error << _("Cannot rename read-only session.") << endmsg;
4222 return 0; // don't show "messed up" warning
4224 if (record_status() == Recording) {
4225 error << _("Cannot rename session while recording") << endmsg;
4226 return 0; // don't show "messed up" warning
4229 StateProtector stp (this);
4234 * interchange subdirectory
4238 * Backup files are left unchanged and not renamed.
4241 /* Windows requires that we close all files before attempting the
4242 * rename. This works on other platforms, but isn't necessary there.
4243 * Leave it in place for all platforms though, since it may help
4244 * catch issues that could arise if the way Source files work ever
4245 * change (since most developers are not using Windows).
4248 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4249 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4255 /* pass one: not 100% safe check that the new directory names don't
4259 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4263 /* this is a stupid hack because Glib::path_get_dirname() is
4264 * lexical-only, and so passing it /a/b/c/ gives a different
4265 * result than passing it /a/b/c ...
4268 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4269 oldstr = oldstr.substr (0, oldstr.length() - 1);
4272 string base = Glib::path_get_dirname (oldstr);
4274 newstr = Glib::build_filename (base, legal_name);
4276 cerr << "Looking for " << newstr << endl;
4278 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4279 cerr << " exists\n";
4288 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4294 /* this is a stupid hack because Glib::path_get_dirname() is
4295 * lexical-only, and so passing it /a/b/c/ gives a different
4296 * result than passing it /a/b/c ...
4299 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4300 oldstr = oldstr.substr (0, oldstr.length() - 1);
4303 string base = Glib::path_get_dirname (oldstr);
4304 newstr = Glib::build_filename (base, legal_name);
4306 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4308 cerr << "Rename " << oldstr << " => " << newstr << endl;
4309 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4310 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4311 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4315 /* Reset path in "session dirs" */
4320 /* reset primary SessionDirectory object */
4323 (*_session_dir) = newstr;
4328 /* now rename directory below session_dir/interchange */
4330 string old_interchange_dir;
4331 string new_interchange_dir;
4333 /* use newstr here because we renamed the path
4334 * (folder/directory) that used to be oldstr to newstr above
4337 v.push_back (newstr);
4338 v.push_back (interchange_dir_name);
4339 v.push_back (Glib::path_get_basename (oldstr));
4341 old_interchange_dir = Glib::build_filename (v);
4344 v.push_back (newstr);
4345 v.push_back (interchange_dir_name);
4346 v.push_back (legal_name);
4348 new_interchange_dir = Glib::build_filename (v);
4350 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4352 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4353 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4354 old_interchange_dir, new_interchange_dir,
4357 error << string_compose (_("renaming %s as %2 failed (%3)"),
4358 old_interchange_dir, new_interchange_dir,
4367 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4368 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4370 cerr << "Rename " << oldstr << " => " << newstr << endl;
4372 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4373 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4374 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4380 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4382 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4383 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4385 cerr << "Rename " << oldstr << " => " << newstr << endl;
4387 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4388 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4389 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4394 /* remove old name from recent sessions */
4395 remove_recent_sessions (_path);
4398 /* update file source paths */
4400 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4401 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4403 string p = fs->path ();
4404 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4406 SourceFactory::setup_peakfile(i->second, true);
4410 set_snapshot_name (new_name);
4415 /* save state again to get everything just right */
4417 save_state (_current_snapshot_name);
4419 /* add to recent sessions */
4421 store_recent_sessions (new_name, _path);
4427 Session::parse_stateful_loading_version (const std::string& version)
4429 if (version.empty ()) {
4430 /* no version implies very old version of Ardour */
4434 if (version.find ('.') != string::npos) {
4435 /* old school version format */
4436 if (version[0] == '2') {
4442 return string_to<int32_t>(version);
4447 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4449 bool found_sr = false;
4450 bool found_data_format = false;
4451 std::string version;
4452 program_version = "";
4454 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4458 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4462 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4465 xmlFreeParserCtxt(ctxt);
4469 xmlNodePtr node = xmlDocGetRootElement(doc);
4472 xmlFreeParserCtxt(ctxt);
4477 /* sample rate & version*/
4480 for (attr = node->properties; attr; attr = attr->next) {
4481 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4482 version = std::string ((char*)attr->children->content);
4484 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4485 sample_rate = atoi ((char*)attr->children->content);
4490 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4494 node = node->children;
4495 while (node != NULL) {
4496 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4497 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4499 program_version = string ((const char*)val);
4500 size_t sep = program_version.find_first_of("-");
4501 if (sep != string::npos) {
4502 program_version = program_version.substr (0, sep);
4507 if (strcmp((const char*) node->name, "Config")) {
4511 for (node = node->children; node; node = node->next) {
4512 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4513 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4515 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4518 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4520 found_data_format = true;
4521 } catch (PBD::unknown_enumeration& e) {}
4531 xmlFreeParserCtxt(ctxt);
4534 return (found_sr && found_data_format) ? 0 : 1;
4538 Session::get_snapshot_from_instant (const std::string& session_dir)
4540 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4542 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4547 if (!tree.read (instant_xml_path)) {
4551 XMLProperty const * prop;
4552 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4553 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4554 return prop->value();
4560 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4561 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4564 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4568 SourcePathMap source_path_map;
4570 boost::shared_ptr<AudioFileSource> afs;
4575 Glib::Threads::Mutex::Lock lm (source_lock);
4577 cerr << " total sources = " << sources.size();
4579 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4580 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4586 if (fs->within_session()) {
4590 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4591 source_path_map[fs->path()].push_back (fs);
4593 SeveralFileSources v;
4595 source_path_map.insert (make_pair (fs->path(), v));
4601 cerr << " fsources = " << total << endl;
4603 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4605 /* tell caller where we are */
4607 string old_path = i->first;
4609 callback (n, total, old_path);
4611 cerr << old_path << endl;
4615 switch (i->second.front()->type()) {
4616 case DataType::AUDIO:
4617 new_path = new_audio_source_path_for_embedded (old_path);
4620 case DataType::MIDI:
4621 /* XXX not implemented yet */
4625 if (new_path.empty()) {
4629 cerr << "Move " << old_path << " => " << new_path << endl;
4631 if (!copy_file (old_path, new_path)) {
4632 cerr << "failed !\n";
4636 /* make sure we stop looking in the external
4637 dir/folder. Remember, this is an all-or-nothing
4638 operations, it doesn't merge just some files.
4640 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4642 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4643 (*f)->set_path (new_path);
4648 save_state ("", false, false);
4654 bool accept_all_files (string const &, void *)
4660 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4662 /* 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.
4667 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4669 // old_path must be in within_session ()
4670 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4672 v.push_back (new_session_folder); /* full path */
4673 v.push_back (interchange_dir_name);
4674 v.push_back (new_session_name); /* just one directory/folder */
4675 v.push_back (typedir);
4676 v.push_back (Glib::path_get_basename (old_path));
4678 return Glib::build_filename (v);
4682 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4685 v.push_back (new_session_folder); /* full path */
4686 v.push_back (interchange_dir_name);
4687 v.push_back (new_session_name);
4688 v.push_back (ARDOUR::sound_dir_name);
4689 v.push_back (filename);
4691 return Glib::build_filename (v);
4695 Session::save_as (SaveAs& saveas)
4697 vector<string> files;
4698 string current_folder = Glib::path_get_dirname (_path);
4699 string new_folder = legalize_for_path (saveas.new_name);
4700 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4701 int64_t total_bytes = 0;
4705 int32_t internal_file_cnt = 0;
4707 vector<string> do_not_copy_extensions;
4708 do_not_copy_extensions.push_back (statefile_suffix);
4709 do_not_copy_extensions.push_back (pending_suffix);
4710 do_not_copy_extensions.push_back (backup_suffix);
4711 do_not_copy_extensions.push_back (temp_suffix);
4712 do_not_copy_extensions.push_back (history_suffix);
4714 /* get total size */
4716 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4718 /* need to clear this because
4719 * find_files_matching_filter() is cumulative
4724 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4726 all += files.size();
4728 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4730 g_stat ((*i).c_str(), &gsb);
4731 total_bytes += gsb.st_size;
4735 /* save old values so we can switch back if we are not switching to the new session */
4737 string old_path = _path;
4738 string old_name = _name;
4739 string old_snapshot = _current_snapshot_name;
4740 string old_sd = _session_dir->root_path();
4741 vector<string> old_search_path[DataType::num_types];
4742 string old_config_search_path[DataType::num_types];
4744 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4745 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4746 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4747 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4749 /* switch session directory */
4751 (*_session_dir) = to_dir;
4753 /* create new tree */
4755 if (!_session_dir->create()) {
4756 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4761 /* copy all relevant files. Find each location in session_dirs,
4762 * and copy files from there to target.
4765 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4767 /* need to clear this because
4768 * find_files_matching_filter() is cumulative
4773 const size_t prefix_len = (*sd).path.size();
4775 /* Work just on the files within this session dir */
4777 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4779 /* add dir separator to protect against collisions with
4780 * track names (e.g. track named "audiofiles" or
4784 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4785 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4786 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4788 /* copy all the files. Handling is different for media files
4789 than others because of the *silly* subtree we have below the interchange
4790 folder. That really was a bad idea, but I'm not fixing it as part of
4791 implementing ::save_as().
4794 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4796 std::string from = *i;
4799 string filename = Glib::path_get_basename (from);
4800 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4801 if (filename == ".DS_STORE") {
4806 if (from.find (audiofile_dir_string) != string::npos) {
4808 /* audio file: only copy if asked */
4810 if (saveas.include_media && saveas.copy_media) {
4812 string to = make_new_media_path (*i, to_dir, new_folder);
4814 info << "media file copying from " << from << " to " << to << endmsg;
4816 if (!copy_file (from, to)) {
4817 throw Glib::FileError (Glib::FileError::IO_ERROR,
4818 string_compose(_("\ncopying \"%1\" failed !"), from));
4822 /* we found media files inside the session folder */
4824 internal_file_cnt++;
4826 } else if (from.find (midifile_dir_string) != string::npos) {
4828 /* midi file: always copy unless
4829 * creating an empty new session
4832 if (saveas.include_media) {
4834 string to = make_new_media_path (*i, to_dir, new_folder);
4836 info << "media file copying from " << from << " to " << to << endmsg;
4838 if (!copy_file (from, to)) {
4839 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4843 /* we found media files inside the session folder */
4845 internal_file_cnt++;
4847 } else if (from.find (analysis_dir_string) != string::npos) {
4849 /* make sure analysis dir exists in
4850 * new session folder, but we're not
4851 * copying analysis files here, see
4855 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4860 /* normal non-media file. Don't copy state, history, etc.
4863 bool do_copy = true;
4865 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4866 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4867 /* end of filename matches extension, do not copy file */
4873 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4874 /* don't copy peakfiles if
4875 * we're not copying media
4881 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4883 info << "attempting to make directory/folder " << to << endmsg;
4885 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4886 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4889 info << "attempting to copy " << from << " to " << to << endmsg;
4891 if (!copy_file (from, to)) {
4892 throw Glib::FileError (Glib::FileError::IO_ERROR,
4893 string_compose(_("\ncopying \"%1\" failed !"), from));
4898 /* measure file size even if we're not going to copy so that our Progress
4899 signals are correct, since we included these do-not-copy files
4900 in the computation of the total size and file count.
4904 g_stat (from.c_str(), &gsb);
4905 copied += gsb.st_size;
4908 double fraction = (double) copied / total_bytes;
4910 bool keep_going = true;
4912 if (saveas.copy_media) {
4914 /* no need or expectation of this if
4915 * media is not being copied, because
4916 * it will be fast(ish).
4919 /* tell someone "X percent, file M of N"; M is one-based */
4921 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4929 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4935 /* copy optional folders, if any */
4937 string old = plugins_dir ();
4938 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4939 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4940 copy_files (old, newdir);
4943 old = externals_dir ();
4944 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4945 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4946 copy_files (old, newdir);
4949 old = automation_dir ();
4950 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4951 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4952 copy_files (old, newdir);
4955 if (saveas.include_media) {
4957 if (saveas.copy_media) {
4958 #ifndef PLATFORM_WINDOWS
4959 /* There are problems with analysis files on
4960 * Windows, because they used a colon in their
4961 * names as late as 4.0. Colons are not legal
4962 * under Windows even if NTFS allows them.
4964 * This is a tricky problem to solve so for
4965 * just don't copy these files. They will be
4966 * regenerated as-needed anyway, subject to the
4967 * existing issue that the filenames will be
4968 * rejected by Windows, which is a separate
4969 * problem (though related).
4972 /* only needed if we are copying media, since the
4973 * analysis data refers to media data
4976 old = analysis_dir ();
4977 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4978 string newdir = Glib::build_filename (to_dir, "analysis");
4979 copy_files (old, newdir);
4981 #endif /* PLATFORM_WINDOWS */
4986 set_snapshot_name (saveas.new_name);
4987 _name = saveas.new_name;
4989 if (saveas.include_media && !saveas.copy_media) {
4991 /* reset search paths of the new session (which we're pretending to be right now) to
4992 include the original session search path, so we can still find all audio.
4995 if (internal_file_cnt) {
4996 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4997 ensure_search_path_includes (*s, DataType::AUDIO);
4998 cerr << "be sure to include " << *s << " for audio" << endl;
5001 /* we do not do this for MIDI because we copy
5002 all MIDI files if saveas.include_media is
5008 bool was_dirty = dirty ();
5010 save_default_options ();
5012 if (saveas.copy_media && saveas.copy_external) {
5013 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5014 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5018 saveas.final_session_folder_name = _path;
5020 store_recent_sessions (_name, _path);
5022 if (!saveas.switch_to) {
5024 /* save the new state */
5026 save_state ("", false, false, !saveas.include_media);
5028 /* switch back to the way things were */
5032 set_snapshot_name (old_snapshot);
5034 (*_session_dir) = old_sd;
5040 if (internal_file_cnt) {
5041 /* reset these to their original values */
5042 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5043 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5048 /* prune session dirs, and update disk space statistics
5053 session_dirs.clear ();
5054 session_dirs.push_back (sp);
5055 refresh_disk_space ();
5057 _writable = exists_and_writable (_path);
5059 /* ensure that all existing tracks reset their current capture source paths
5061 reset_write_sources (true, true);
5063 /* creating new write sources marks the session as
5064 dirty. If the new session is empty, then
5065 save_state() thinks we're saving a template and will
5066 not mark the session as clean. So do that here,
5067 before we save state.
5070 if (!saveas.include_media) {
5071 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5074 save_state ("", false, false, !saveas.include_media);
5076 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5077 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5080 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5081 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5087 if (fs->within_session()) {
5088 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5089 fs->set_path (newpath);
5094 } catch (Glib::FileError& e) {
5096 saveas.failure_message = e.what();
5098 /* recursively remove all the directories */
5100 remove_directory (to_dir);
5108 saveas.failure_message = _("unknown reason");
5110 /* recursively remove all the directories */
5112 remove_directory (to_dir);
5122 static void set_progress (Progress* p, size_t n, size_t t)
5124 p->set_progress (float (n) / float(t));
5128 Session::archive_session (const std::string& dest,
5129 const std::string& name,
5130 ArchiveEncode compress_audio,
5131 FileArchive::CompressionLevel compression_level,
5132 bool only_used_sources,
5135 if (dest.empty () || name.empty ()) {
5139 /* We are going to temporarily change some source properties,
5140 * don't allow any concurrent saves (periodic or otherwise */
5141 Glib::Threads::Mutex::Lock lm (save_source_lock);
5143 disable_record (false);
5145 /* save current values */
5146 string old_path = _path;
5147 string old_name = _name;
5148 string old_snapshot = _current_snapshot_name;
5149 string old_sd = _session_dir->root_path();
5150 string old_config_search_path[DataType::num_types];
5151 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5152 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5154 /* ensure that session-path is included in search-path */
5156 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5157 if ((*sd).path == old_path) {
5165 /* create temporary dir to save session to */
5166 #ifdef PLATFORM_WINDOWS
5167 char tmp[256] = "C:\\TEMP\\";
5168 GetTempPath (sizeof (tmp), tmp);
5170 char const* tmp = getenv("TMPDIR");
5175 if ((strlen (tmp) + 21) > 1024) {
5180 strcpy (tmptpl, tmp);
5181 strcat (tmptpl, "ardourarchive-XXXXXX");
5182 char* tmpdir = g_mkdtemp (tmptpl);
5188 std::string to_dir = std::string (tmpdir);
5190 /* switch session directory temporarily */
5191 (*_session_dir) = to_dir;
5193 if (!_session_dir->create()) {
5194 (*_session_dir) = old_sd;
5195 remove_directory (to_dir);
5199 /* prepare archive */
5200 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5202 PBD::ScopedConnectionList progress_connection;
5203 PBD::FileArchive ar (archive);
5205 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5208 /* collect files to archive */
5209 std::map<string,string> filemap;
5211 vector<string> do_not_copy_extensions;
5212 do_not_copy_extensions.push_back (statefile_suffix);
5213 do_not_copy_extensions.push_back (pending_suffix);
5214 do_not_copy_extensions.push_back (backup_suffix);
5215 do_not_copy_extensions.push_back (temp_suffix);
5216 do_not_copy_extensions.push_back (history_suffix);
5218 vector<string> blacklist_dirs;
5219 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5220 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5221 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5222 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5223 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5224 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5226 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5227 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5228 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5230 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5231 if (only_used_sources) {
5232 playlists->sync_all_regions_with_regions ();
5233 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5236 /* collect audio sources for this session, calc total size for encoding
5237 * add option to only include *used* sources (see Session::cleanup_sources)
5239 size_t total_size = 0;
5241 Glib::Threads::Mutex::Lock lm (source_lock);
5243 /* build a list of used names */
5244 std::set<std::string> audio_file_names;
5245 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5246 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5247 if (!afs || afs->readable_length () == 0) {
5250 if (only_used_sources) {
5254 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5258 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5261 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5262 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5263 if (!afs || afs->readable_length () == 0) {
5267 if (only_used_sources) {
5271 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5276 std::string from = afs->path();
5278 if (compress_audio != NO_ENCODE) {
5279 total_size += afs->readable_length ();
5281 /* copy files as-is */
5282 if (!afs->within_session()) {
5283 string to = Glib::path_get_basename (from);
5285 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5286 * - avoid conflict with files existing in interchange
5287 * - avoid conflict with other embedded sources
5289 if (audio_file_names.find (to) == audio_file_names.end ()) {
5290 // we need a new name, add a '-<num>' before the '.<ext>'
5291 string bn = to.substr (0, to.find_last_of ('.'));
5292 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5293 to = bn + "-1" + ext;
5295 while (audio_file_names.find (to) == audio_file_names.end ()) {
5296 to = bump_name_once (to, '-');
5299 audio_file_names.insert (to);
5300 filemap[from] = make_new_audio_path (to, name, name);
5302 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5304 orig_origin[afs] = afs->origin ();
5305 afs->set_origin ("");
5308 filemap[from] = make_new_media_path (from, name, name);
5315 if (compress_audio != NO_ENCODE) {
5317 progress->set_progress (2); // set to "encoding"
5318 progress->set_progress (0);
5321 Glib::Threads::Mutex::Lock lm (source_lock);
5322 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5323 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5324 if (!afs || afs->readable_length () == 0) {
5328 if (only_used_sources) {
5332 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5337 orig_sources[afs] = afs->path();
5338 orig_gain[afs] = afs->gain();
5340 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5342 std::string channelsuffix = "";
5343 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5344 /* embedded external multi-channel files are converted to multiple-mono */
5345 channelsuffix = string_compose ("-c%1", afs->channel ());
5347 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5348 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5350 /* avoid name collisions of external files with same name */
5351 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5352 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5354 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5355 new_path = bump_name_once (new_path, '-');
5359 progress->descend ((float)afs->readable_length () / total_size);
5363 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5364 afs->replace_file (new_path);
5365 afs->set_gain (ns->gain(), true);
5368 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5372 progress->ascend ();
5378 progress->set_progress (-1); // set to "archiving"
5379 progress->set_progress (0);
5382 /* index files relevant for this session */
5383 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5384 vector<string> files;
5386 size_t prefix_len = (*sd).path.size();
5387 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5391 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5393 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5394 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5395 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5397 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5398 std::string from = *i;
5401 string filename = Glib::path_get_basename (from);
5402 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5403 if (filename == ".DS_STORE") {
5408 if (from.find (audiofile_dir_string) != string::npos) {
5410 } else if (from.find (midifile_dir_string) != string::npos) {
5411 filemap[from] = make_new_media_path (from, name, name);
5412 } else if (from.find (videofile_dir_string) != string::npos) {
5413 filemap[from] = make_new_media_path (from, name, name);
5415 bool do_copy = true;
5416 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5417 if (from.find (*v) != string::npos) {
5422 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5423 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5430 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5436 /* write session file */
5438 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5440 save_state (name, false, false, false, true, only_used_sources);
5442 save_default_options ();
5444 size_t prefix_len = _path.size();
5445 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5449 /* collect session-state files */
5450 vector<string> files;
5451 do_not_copy_extensions.clear ();
5452 do_not_copy_extensions.push_back (history_suffix);
5454 blacklist_dirs.clear ();
5455 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5457 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5458 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5459 std::string from = *i;
5460 bool do_copy = true;
5461 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5462 if (from.find (*v) != string::npos) {
5467 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5468 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5474 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5478 /* restore original values */
5481 set_snapshot_name (old_snapshot);
5482 (*_session_dir) = old_sd;
5483 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5484 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5486 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5487 i->first->set_origin (i->second);
5489 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5490 i->first->replace_file (i->second);
5492 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5493 i->first->set_gain (i->second, true);
5496 int rv = ar.create (filemap, compression_level);
5497 remove_directory (to_dir);
5503 Session::undo (uint32_t n)
5505 if (actively_recording()) {
5513 Session::redo (uint32_t n)
5515 if (actively_recording()) {