2 * Copyright (C) 1999-2019 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
5 * Copyright (C) 2006-2016 Tim Mayberry <mojofunk@gmail.com>
6 * Copyright (C) 2006 Jesse Chappell <jesse@essej.net>
7 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8 * Copyright (C) 2008-2009 Hans Baier <hansfbaier@googlemail.com>
9 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
10 * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
11 * Copyright (C) 2013-2017 Nick Mainsbridge <mainsbridge@gmail.com>
12 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
13 * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include "libardour-config.h"
40 #include <cstdio> /* snprintf(3) ... grrr */
52 #if defined(__APPLE__) || defined(__FreeBSD__)
53 #include <sys/param.h>
54 #include <sys/mount.h>
57 #ifdef HAVE_SYS_STATVFS_H
58 #include <sys/statvfs.h>
62 #include "pbd/gstdio_compat.h"
63 #include "pbd/locale_guard.h"
66 #include <glibmm/threads.h>
67 #include <glibmm/fileutils.h>
69 #include <boost/algorithm/string.hpp>
71 #include "midi++/mmc.h"
72 #include "midi++/port.h"
74 #include "evoral/SMF.h"
76 #include "pbd/basename.h"
77 #include "pbd/debug.h"
78 #include "pbd/enumwriter.h"
79 #include "pbd/error.h"
80 #include "pbd/file_utils.h"
81 #include "pbd/pathexpand.h"
82 #include "pbd/pthread_utils.h"
83 #include "pbd/stacktrace.h"
84 #include "pbd/types_convert.h"
85 #include "pbd/localtime_r.h"
86 #include "pbd/unwind.h"
88 #include "ardour/amp.h"
89 #include "ardour/async_midi_port.h"
90 #include "ardour/audio_track.h"
91 #include "ardour/audioengine.h"
92 #include "ardour/audiofilesource.h"
93 #include "ardour/audioregion.h"
94 #include "ardour/auditioner.h"
95 #include "ardour/automation_control.h"
96 #include "ardour/boost_debug.h"
97 #include "ardour/butler.h"
98 #include "ardour/control_protocol_manager.h"
99 #include "ardour/directory_names.h"
100 #include "ardour/disk_reader.h"
101 #include "ardour/filename_extensions.h"
102 #include "ardour/graph.h"
103 #include "ardour/location.h"
105 #include "ardour/lv2_plugin.h"
107 #include "ardour/midi_model.h"
108 #include "ardour/midi_patch_manager.h"
109 #include "ardour/midi_region.h"
110 #include "ardour/midi_scene_changer.h"
111 #include "ardour/midi_source.h"
112 #include "ardour/midi_track.h"
113 #include "ardour/pannable.h"
114 #include "ardour/playlist_factory.h"
115 #include "ardour/playlist_source.h"
116 #include "ardour/port.h"
117 #include "ardour/processor.h"
118 #include "ardour/progress.h"
119 #include "ardour/profile.h"
120 #include "ardour/proxy_controllable.h"
121 #include "ardour/recent_sessions.h"
122 #include "ardour/region_factory.h"
123 #include "ardour/revision.h"
124 #include "ardour/route_group.h"
125 #include "ardour/send.h"
126 #include "ardour/selection.h"
127 #include "ardour/session.h"
128 #include "ardour/session_directory.h"
129 #include "ardour/session_metadata.h"
130 #include "ardour/session_playlists.h"
131 #include "ardour/session_state_utils.h"
132 #include "ardour/silentfilesource.h"
133 #include "ardour/smf_source.h"
134 #include "ardour/sndfilesource.h"
135 #include "ardour/source_factory.h"
136 #include "ardour/speakers.h"
137 #include "ardour/template_utils.h"
138 #include "ardour/tempo.h"
139 #include "ardour/ticker.h"
140 #include "ardour/transport_master_manager.h"
141 #include "ardour/types_convert.h"
142 #include "ardour/user_bundle.h"
143 #include "ardour/vca.h"
144 #include "ardour/vca_manager.h"
146 #include "control_protocol/control_protocol.h"
148 #include "LuaBridge/LuaBridge.h"
150 #include "pbd/i18n.h"
154 using namespace ARDOUR;
157 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
160 Session::pre_engine_init (string fullpath)
162 if (fullpath.empty()) {
164 throw failed_constructor();
167 /* discover canonical fullpath */
169 _path = canonical_path(fullpath);
173 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
175 /* finish initialization that can't be done in a normal C++ constructor
179 timerclear (&last_mmc_step);
180 g_atomic_int_set (&processing_prohibited, 0);
181 g_atomic_int_set (&_record_status, Disabled);
182 g_atomic_int_set (&_playback_load, 100);
183 g_atomic_int_set (&_capture_load, 100);
185 _all_route_group->set_active (true, this);
187 if (config.get_use_video_sync()) {
188 waiting_for_sync_offset = true;
190 waiting_for_sync_offset = false;
193 last_rr_session_dir = session_dirs.begin();
195 set_history_depth (Config->get_history_depth());
197 /* default: assume simple stereo speaker configuration */
199 _speakers->setup_default_speakers (2);
201 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
202 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
203 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
204 add_controllable (_solo_cut_control);
206 /* These are all static "per-class" signals */
208 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
209 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
210 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
211 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
213 /* stop IO objects from doing stuff until we're ready for them */
215 Delivery::disable_panners ();
216 IO::disable_connecting ();
220 Session::post_engine_init ()
222 BootMessage (_("Set block size and sample rate"));
224 set_block_size (_engine.samples_per_cycle());
225 set_sample_rate (_engine.sample_rate());
227 BootMessage (_("Using configuration"));
229 _midi_ports = new MidiPortManager;
231 MIDISceneChanger* msc;
233 _scene_changer = msc = new MIDISceneChanger (*this);
234 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
235 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
237 boost::function<samplecnt_t(void)> timer_func (boost::bind (&Session::audible_sample, this, (bool*)(0)));
238 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
240 setup_midi_machine_control ();
242 if (_butler->start_thread()) {
243 error << _("Butler did not start") << endmsg;
247 if (start_midi_thread ()) {
248 error << _("MIDI I/O thread did not start") << endmsg;
252 setup_click_sounds (0);
253 setup_midi_control ();
255 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
256 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
259 /* tempo map requires sample rate knowledge */
262 _tempo_map = new TempoMap (_current_sample_rate);
263 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
264 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
265 } catch (std::exception const & e) {
266 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
269 error << _("Unknown exception during session setup") << endmsg;
274 /* MidiClock requires a tempo map */
277 midi_clock = new MidiClockTicker ();
278 midi_clock->set_session (this);
280 /* crossfades require sample rate knowledge */
282 SndFileSource::setup_standard_crossfades (*this, sample_rate());
283 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this, true));
284 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
286 DiskReader::allocate_working_buffers();
287 refresh_disk_space ();
289 /* we're finally ready to call set_state() ... all objects have
290 * been created, the engine is running.
295 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
296 error << _("Could not set session state from XML") << endmsg;
299 } catch (PBD::unknown_enumeration& e) {
300 error << _("Session state: ") << e.what() << endmsg;
304 // set_state() will call setup_raid_path(), but if it's a new session we need
305 // to call setup_raid_path() here.
306 setup_raid_path (_path);
311 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
312 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
314 Config->map_parameters (ff);
315 config.map_parameters (ft);
316 _butler->map_parameters ();
318 /* Configure all processors; now that the
319 * engine is running, ports are re-established,
320 * and IOChange are complete.
323 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
324 ProcessorChangeBlocker pcb (this);
325 boost::shared_ptr<RouteList> r = routes.reader ();
326 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
327 (*i)->configure_processors (0);
331 /* Reset all panners */
333 Delivery::reset_panners ();
335 /* this will cause the CPM to instantiate any protocols that are in use
336 * (or mandatory), which will pass it this Session, and then call
337 * set_state() on each instantiated protocol to match stored state.
340 ControlProtocolManager::instance().set_session (this);
342 /* This must be done after the ControlProtocolManager set_session above,
343 as it will set states for ports which the ControlProtocolManager creates.
346 // XXX set state of MIDI::Port's
347 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
349 /* And this must be done after the MIDI::Manager::set_port_states as
350 * it will try to make connections whose details are loaded by set_port_states.
355 /* Let control protocols know that we are now all connected, so they
356 * could start talking to surfaces if they want to.
359 ControlProtocolManager::instance().midi_connectivity_established ();
361 if (_is_new && !no_auto_connect()) {
362 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
363 auto_connect_master_bus ();
366 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave | Dirty));
368 /* update latencies */
370 initialize_latencies ();
372 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
373 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
374 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
376 if (synced_to_engine()) {
377 _engine.transport_stop ();
380 // send_full_time_code (0);
382 } catch (AudioEngine::PortRegistrationFailure& err) {
383 error << err.what() << endmsg;
385 } catch (std::exception const & e) {
386 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
389 error << _("Unknown exception during session setup") << endmsg;
393 BootMessage (_("Reset Remote Controls"));
395 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
396 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
400 BootMessage (_("Loading MIDNAM Patch files"));
402 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
403 /* initial program change will be delivered later; see ::config_changed() */
405 _state_of_the_state = Clean;
407 Port::set_connecting_blocked (false);
409 DirtyChanged (); /* EMIT SIGNAL */
411 /* Now, finally, we can fill the playback buffers */
413 BootMessage (_("Filling playback buffers"));
415 boost::shared_ptr<RouteList> rl = routes.reader();
416 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
417 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
418 if (trk && !trk->is_private_route()) {
419 trk->seek (_transport_sample, true);
427 Session::session_loaded ()
431 _state_of_the_state = Clean;
433 DirtyChanged (); /* EMIT SIGNAL */
437 } else if (state_was_pending) {
439 state_was_pending = false;
442 /* Now, finally, we can fill the playback buffers */
444 BootMessage (_("Filling playback buffers"));
445 force_locate (_transport_sample, false);
449 Session::raid_path () const
451 Searchpath raid_search_path;
453 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
454 raid_search_path += (*i).path;
457 return raid_search_path.to_string ();
461 Session::setup_raid_path (string path)
470 session_dirs.clear ();
472 Searchpath search_path(path);
473 Searchpath sound_search_path;
474 Searchpath midi_search_path;
476 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
478 sp.blocks = 0; // not needed
479 session_dirs.push_back (sp);
481 SessionDirectory sdir(sp.path);
483 sound_search_path += sdir.sound_path ();
484 midi_search_path += sdir.midi_path ();
487 // reset the round-robin soundfile path thingie
488 last_rr_session_dir = session_dirs.begin();
492 Session::path_is_within_session (const std::string& path)
494 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
495 if (PBD::path_is_within (i->path, path)) {
503 Session::ensure_subdirs ()
507 dir = session_directory().peak_path();
509 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
510 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
514 dir = session_directory().sound_path();
516 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
517 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
521 dir = session_directory().midi_path();
523 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
524 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
528 dir = session_directory().dead_path();
530 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
531 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
535 dir = session_directory().export_path();
537 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
538 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
542 if(Profile->get_mixbus()) {
543 dir = session_directory().backup_path();
545 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
546 error << string_compose(_("Session: cannot create session backup folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
551 dir = analysis_dir ();
553 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
554 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
558 dir = plugins_dir ();
560 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
561 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
565 dir = externals_dir ();
567 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
568 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
575 /** @param session_template directory containing session template, or empty.
576 * Caller must not hold process lock.
579 Session::create (const string& session_template, BusProfile const * bus_profile)
581 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
582 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
586 if (ensure_subdirs ()) {
590 _writable = exists_and_writable (_path);
592 if (!session_template.empty()) {
593 string in_path = session_template_dir_to_file (session_template);
595 FILE* in = g_fopen (in_path.c_str(), "rb");
598 /* no need to call legalize_for_path() since the string
599 * in session_template is already a legal path name
601 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
603 FILE* out = g_fopen (out_path.c_str(), "wb");
607 stringstream new_session;
610 size_t charsRead = fread (buf, sizeof(char), 1024, in);
613 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
618 if (charsRead == 0) {
621 new_session.write (buf, charsRead);
625 string file_contents = new_session.str();
626 size_t writeSize = file_contents.length();
627 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
628 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
636 /* Copy plugin state files from template to new session */
637 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
638 copy_recurse (template_plugins, plugins_dir ());
643 error << string_compose (_("Could not open %1 for writing session template"), out_path)
650 error << string_compose (_("Could not open session template %1 for reading"), in_path)
657 _state_of_the_state = Clean;
659 /* set up Master Out and Monitor Out if necessary */
663 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
664 if (bus_profile->master_out_channels) {
665 int rv = add_master_bus (count);
671 if (Config->get_use_monitor_bus())
672 add_monitor_section ();
680 Session::maybe_write_autosave()
682 if (dirty() && record_status() != Recording) {
683 save_state("", true);
688 Session::remove_pending_capture_state ()
690 std::string pending_state_file_path(_session_dir->root_path());
692 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
694 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) {
698 if (::g_unlink (pending_state_file_path.c_str()) != 0) {
699 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
700 pending_state_file_path, g_strerror (errno)) << endmsg;
704 cerr << "removed " << pending_state_file_path << endl;
709 /** Rename a state file.
710 * @param old_name Old snapshot name.
711 * @param new_name New snapshot name.
714 Session::rename_state (string old_name, string new_name)
716 if (old_name == _current_snapshot_name || old_name == _name) {
717 /* refuse to rename the current snapshot or the "main" one */
721 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
722 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
724 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
725 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
727 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
728 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
729 old_name, new_name, g_strerror(errno)) << endmsg;
733 /** Remove a state file.
734 * @param snapshot_name Snapshot name.
737 Session::remove_state (string snapshot_name)
739 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
740 // refuse to remove the current snapshot or the "main" one
744 std::string xml_path(_session_dir->root_path());
746 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
748 if (!create_backup_file (xml_path)) {
749 // don't remove it if a backup can't be made
750 // create_backup_file will log the error.
755 if (g_remove (xml_path.c_str()) != 0) {
756 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
757 xml_path, g_strerror (errno)) << endmsg;
760 StateSaved (snapshot_name); /* EMIT SIGNAL */
763 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
765 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only, bool for_archive, bool only_used_assets)
767 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
770 std::string xml_path(_session_dir->root_path());
772 /* prevent concurrent saves from different threads */
774 Glib::Threads::Mutex::Lock lm (save_state_lock);
775 Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK);
780 if (!_writable || cannot_save()) {
784 if (g_atomic_int_get(&_suspend_save)) {
788 _save_queued = false;
790 snapshot_t fork_state = NormalSave;
791 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) {
792 /* snapshot, close midi */
793 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
797 const int64_t save_start_time = g_get_monotonic_time();
800 /* tell sources we're saving first, in case they write out to a new file
801 * which should be saved with the state rather than the old one */
802 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
804 i->second->session_saved();
805 } catch (Evoral::SMF::FileError& e) {
806 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
810 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, for_archive);
812 SessionSaveUnderway (); /* EMIT SIGNAL */
814 bool mark_as_clean = true;
815 if (!snapshot_name.empty() && !switch_to_snapshot) {
816 mark_as_clean = false;
820 mark_as_clean = false;
821 tree.set_root (&get_template());
823 tree.set_root (&state (false, fork_state, only_used_assets));
826 if (snapshot_name.empty()) {
827 snapshot_name = _current_snapshot_name;
828 } else if (switch_to_snapshot) {
829 set_snapshot_name (snapshot_name);
832 assert (!snapshot_name.empty());
836 /* proper save: use statefile_suffix (.ardour in English) */
838 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
840 /* make a backup copy of the old file */
842 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
843 // create_backup_file will log the error
848 assert (snapshot_name == _current_snapshot_name);
849 /* pending save: use pending_suffix (.pending in English) */
850 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
853 std::string tmp_path(_session_dir->root_path());
854 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
857 cerr << "actually writing state to " << tmp_path << endl;
860 if (!tree.write (tmp_path)) {
861 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
862 if (g_remove (tmp_path.c_str()) != 0) {
863 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
864 tmp_path, g_strerror (errno)) << endmsg;
871 cerr << "renaming state to " << xml_path << endl;
874 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
875 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
876 tmp_path, xml_path, g_strerror(errno)) << endmsg;
877 if (g_remove (tmp_path.c_str()) != 0) {
878 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
879 tmp_path, g_strerror (errno)) << endmsg;
885 //Mixbus auto-backup mechanism
886 if(Profile->get_mixbus()) {
887 if (pending) { //"pending" save means it's a backup, or some other non-user-initiated save; a good time to make a backup
888 // make a serialized safety backup
889 // (will make one periodically but only one per hour is left on disk)
890 // these backup files go into a separated folder
893 struct tm local_time;
895 localtime_r (&n, &local_time);
896 strftime (timebuf, sizeof(timebuf), "%y-%m-%d.%H", &local_time);
897 std::string save_path(session_directory().backup_path());
898 save_path += G_DIR_SEPARATOR;
899 save_path += legalize_for_path(_current_snapshot_name);
901 save_path += timebuf;
902 save_path += statefile_suffix;
903 if ( !tree.write (save_path) )
904 error << string_compose(_("Could not save backup file at path \"%1\" (%2)"),
905 save_path, g_strerror (errno)) << endmsg;
908 StateSaved (snapshot_name); /* EMIT SIGNAL */
911 if (!pending && !for_archive) {
913 save_history (snapshot_name);
916 unset_dirty (/* EMIT SIGNAL */ true);
919 StateSaved (snapshot_name); /* EMIT SIGNAL */
923 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
924 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
927 if (!pending && !for_archive && ! template_only) {
928 remove_pending_capture_state ();
935 Session::restore_state (string snapshot_name)
938 if (load_state (snapshot_name) == 0) {
939 set_state (*state_tree->root(), Stateful::loading_state_version);
943 // unknown_enumeration
951 Session::load_state (string snapshot_name)
956 state_was_pending = false;
958 /* check for leftover pending state from a crashed capture attempt */
960 std::string xmlpath(_session_dir->root_path());
961 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
963 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
965 /* there is pending state from a crashed capture attempt */
967 boost::optional<int> r = AskAboutPendingState();
968 if (r.value_or (1)) {
969 state_was_pending = true;
973 if (!state_was_pending) {
974 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
977 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
978 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
979 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
980 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
985 state_tree = new XMLTree;
989 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
991 if (!state_tree->read (xmlpath)) {
992 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
998 XMLNode const & root (*state_tree->root());
1000 if (root.name() != X_("Session")) {
1001 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
1007 std::string version;
1008 root.get_property ("version", version);
1009 Stateful::loading_state_version = parse_stateful_loading_version (version);
1011 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
1012 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
1013 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
1016 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1018 std::string backup_path(_session_dir->root_path());
1019 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1020 backup_path = Glib::build_filename (backup_path, backup_filename);
1022 // only create a backup for a given statefile version once
1024 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1026 VersionMismatch (xmlpath, backup_path);
1028 if (!copy_file (xmlpath, backup_path)) {;
1034 save_snapshot_name (snapshot_name);
1040 Session::load_options (const XMLNode& node)
1042 config.set_variables (node);
1047 Session::save_default_options ()
1049 return config.save_state();
1053 Session::get_state ()
1055 /* this is not directly called, but required by PBD::Stateful */
1057 return state (false, NormalSave);
1061 Session::get_template ()
1063 /* if we don't disable rec-enable, diskstreams
1064 will believe they need to store their capture
1065 sources in their state node.
1068 disable_record (false);
1070 return state (true, NormalSave);
1073 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1074 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1077 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1079 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1082 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1086 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1089 XMLNode* node = new XMLNode("TrackState"); // XXX
1092 PlaylistSet playlists; // SessionPlaylists
1095 // these will work with new_route_from_template()
1096 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1097 child = node->add_child ("Routes");
1098 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1099 if ((*i)->is_auditioner()) {
1102 if ((*i)->is_master() || (*i)->is_monitor()) {
1105 child->add_child_nocopy ((*i)->get_state());
1106 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1108 playlists.insert (track->playlist ());
1112 // on load, Regions in the playlists need to resolve and map Source-IDs
1113 // also playlist needs to be merged or created with new-name..
1114 // ... and Diskstream in tracks adjusted to use the correct playlist
1115 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1116 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1117 child->add_child_nocopy ((*i)->get_state ());
1118 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1119 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1120 const Region::SourceList& sl = (*s)->sources ();
1121 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1122 sources.insert (*sli);
1127 child = node->add_child ("Sources");
1128 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1129 child->add_child_nocopy ((*i)->get_state ());
1130 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1132 #ifdef PLATFORM_WINDOWS
1135 string p = fs->path ();
1136 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1140 std::string sn = Glib::build_filename (path, "share.axml");
1143 tree.set_root (node);
1144 return tree.write (sn.c_str());
1148 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
1150 pl->deep_sources (*all_sources);
1155 struct route_id_compare {
1157 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1159 return r1->id () < r2->id ();
1165 Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets)
1168 XMLNode* node = new XMLNode("Session");
1171 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1173 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1175 child = node->add_child ("ProgramVersion");
1176 child->set_property("created-with", created_with);
1178 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1179 child->set_property("modified-with", modified_with);
1181 /* store configuration settings */
1183 if (!save_template) {
1185 node->set_property ("name", _name);
1186 node->set_property ("sample-rate", _base_sample_rate);
1188 if (session_dirs.size() > 1) {
1192 vector<space_and_path>::iterator i = session_dirs.begin();
1193 vector<space_and_path>::iterator next;
1195 ++i; /* skip the first one */
1199 while (i != session_dirs.end()) {
1203 if (next != session_dirs.end()) {
1204 p += G_SEARCHPATH_SEPARATOR;
1213 child = node->add_child ("Path");
1214 child->add_content (p);
1216 node->set_property ("end-is-free", _session_range_is_free); //deprecated, but keep storing this value for compatibility with prior v5.
1217 node->set_property ("session-range-is-free", _session_range_is_free);
1220 /* save the ID counter */
1222 node->set_property ("id-counter", ID::counter());
1224 node->set_property ("name-counter", name_id_counter ());
1226 /* save the event ID counter */
1228 node->set_property ("event-counter", Evoral::event_id_counter());
1230 /* save the VCA counter */
1232 node->set_property ("vca-counter", VCA::get_next_vca_number());
1234 /* various options */
1236 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1237 if (!midi_port_nodes.empty()) {
1238 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1239 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1240 midi_port_stuff->add_child_nocopy (**n);
1242 node->add_child_nocopy (*midi_port_stuff);
1245 XMLNode& cfgxml (config.get_variables ());
1246 if (save_template) {
1247 /* exclude search-paths from template */
1248 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1249 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1250 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1252 node->add_child_nocopy (cfgxml);
1254 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1256 child = node->add_child ("Sources");
1258 if (!save_template) {
1259 Glib::Threads::Mutex::Lock sl (source_lock);
1261 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1263 if (only_used_assets) {
1264 _playlists->sync_all_regions_with_regions ();
1265 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1268 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1270 /* Don't save information about non-file Sources, or
1271 * about non-destructive file sources that are empty
1272 * and unused by any regions.
1274 boost::shared_ptr<FileSource> fs;
1276 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1280 if (!fs->destructive()) {
1281 if (fs->empty() && !fs->used()) {
1286 if (only_used_assets) {
1287 /* skip only unused audio files */
1288 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1289 if (afs && !afs->used()) {
1292 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1297 if (snapshot_type != NormalSave && fs->within_session ()) {
1298 /* copy MIDI sources to new file
1300 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1301 * because the GUI (midi_region) has a direct pointer to the midi-model
1302 * of the source, as does UndoTransaction.
1304 * On the upside, .mid files are not kept open. The file is only open
1305 * when reading the model initially and when flushing the model to disk:
1306 * source->session_saved () or export.
1308 * We can change the _path of the existing source under the hood, keeping
1309 * all IDs, references and pointers intact.
1311 boost::shared_ptr<SMFSource> ms;
1312 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1313 const std::string ancestor_name = ms->ancestor_name();
1314 const std::string base = PBD::basename_nosuffix(ancestor_name);
1315 const string path = new_midi_source_path (base, false);
1317 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1318 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1319 Source::Lock lm (ms->mutex());
1321 // TODO special-case empty, removable() files: just create a new removable.
1322 // (load + write flushes the model and creates the file)
1324 ms->load_model (lm);
1326 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1327 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1329 if (snapshot_type == SnapshotKeep) {
1330 /* keep working on current session.
1332 * Save snapshot-state with the original filename.
1333 * Switch to use new path for future saves of the main session.
1335 child->add_child_nocopy (ms->get_state());
1339 * ~SMFSource unlinks removable() files.
1341 std::string npath (ms->path ());
1342 ms->replace_file (newsrc->path ());
1343 newsrc->replace_file (npath);
1345 if (snapshot_type == SwitchToSnapshot) {
1346 /* save and switch to snapshot.
1348 * Leave the old file in place (as is).
1349 * Snapshot uses new source directly
1351 child->add_child_nocopy (ms->get_state());
1358 child->add_child_nocopy (siter->second->get_state());
1362 child = node->add_child ("Regions");
1364 if (!save_template) {
1365 Glib::Threads::Mutex::Lock rl (region_lock);
1367 if (!only_used_assets) {
1368 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1369 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1370 boost::shared_ptr<Region> r = i->second;
1371 /* only store regions not attached to playlists */
1372 if (r->playlist() == 0) {
1373 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1374 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1376 child->add_child_nocopy (r->get_state ());
1382 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1384 if (!cassocs.empty()) {
1385 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1387 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1388 if (i->first->playlist () == 0 && only_used_assets) {
1391 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1392 can->set_property (X_("copy"), i->first->id());
1393 can->set_property (X_("original"), i->second->id());
1394 ca->add_child_nocopy (*can);
1395 /* see above, child is still "Regions" here */
1396 if (i->second->playlist() == 0 && only_used_assets) {
1397 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1398 child->add_child_nocopy (ar->get_basic_state ());
1400 child->add_child_nocopy (ar->get_state ());
1407 if (!save_template) {
1409 node->add_child_nocopy (_selection->get_state());
1412 node->add_child_nocopy (_locations->get_state());
1415 Locations loc (*this);
1416 const bool was_dirty = dirty();
1417 // for a template, just create a new Locations, populate it
1418 // with the default start and end, and get the state for that.
1419 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1420 range->set (max_samplepos, 0);
1422 XMLNode& locations_state = loc.get_state();
1424 node->add_child_nocopy (locations_state);
1426 /* adding a location above will have marked the session
1427 * dirty. This is an artifact, so fix it if the session wasn't
1436 child = node->add_child ("Bundles");
1438 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1439 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1440 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1442 child->add_child_nocopy (b->get_state());
1447 node->add_child_nocopy (_vca_manager->get_state());
1449 child = node->add_child ("Routes");
1451 boost::shared_ptr<RouteList> r = routes.reader ();
1453 route_id_compare cmp;
1454 RouteList xml_node_order (*r);
1455 xml_node_order.sort (cmp);
1457 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1458 if (!(*i)->is_auditioner()) {
1459 if (save_template) {
1460 child->add_child_nocopy ((*i)->get_template());
1462 child->add_child_nocopy ((*i)->get_state());
1468 _playlists->add_state (node, save_template, !only_used_assets);
1470 child = node->add_child ("RouteGroups");
1471 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1472 child->add_child_nocopy ((*i)->get_state());
1476 XMLNode* gain_child = node->add_child ("Click");
1477 gain_child->add_child_nocopy (_click_io->get_state ());
1478 gain_child->add_child_nocopy (_click_gain->get_state ());
1482 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1483 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1486 node->add_child_nocopy (_speakers->get_state());
1487 node->add_child_nocopy (_tempo_map->get_state());
1488 node->add_child_nocopy (get_control_protocol_state());
1491 node->add_child_copy (*_extra_xml);
1495 Glib::Threads::Mutex::Lock lm (lua_lock);
1498 luabridge::LuaRef savedstate ((*_lua_save)());
1499 saved = savedstate.cast<std::string>();
1501 lua.collect_garbage ();
1504 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1505 std::string b64s (b64);
1508 XMLNode* script_node = new XMLNode (X_("Script"));
1509 script_node->set_property (X_("lua"), LUA_VERSION);
1510 script_node->add_content (b64s);
1511 node->add_child_nocopy (*script_node);
1518 Session::get_control_protocol_state ()
1520 return ControlProtocolManager::instance().get_state ();
1524 Session::set_state (const XMLNode& node, int version)
1531 _state_of_the_state = StateOfTheState (_state_of_the_state | CannotSave);
1533 if (node.name() != X_("Session")) {
1534 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1538 node.get_property ("name", _name);
1540 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1542 _nominal_sample_rate = _base_sample_rate;
1544 assert (AudioEngine::instance()->running ());
1545 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1546 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1547 if (r.value_or (0)) {
1553 created_with = "unknown";
1554 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1555 child->get_property (X_("created-with"), created_with);
1558 setup_raid_path(_session_dir->root_path());
1560 node.get_property (X_("end-is-free"), _session_range_is_free); //deprectated, but use old values if they are in the config
1562 node.get_property (X_("session-range-is-free"), _session_range_is_free);
1565 if (node.get_property (X_("id-counter"), counter)) {
1566 ID::init_counter (counter);
1568 /* old sessions used a timebased counter, so fake
1569 * the startup ID counter based on a standard
1574 ID::init_counter (now);
1577 if (node.get_property (X_("name-counter"), counter)) {
1578 init_name_id_counter (counter);
1581 if (node.get_property (X_("event-counter"), counter)) {
1582 Evoral::init_event_id_counter (counter);
1585 if (node.get_property (X_("vca-counter"), counter)) {
1586 VCA::set_next_vca_number (counter);
1588 VCA::set_next_vca_number (1);
1591 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1592 _midi_ports->set_midi_port_states (child->children());
1595 IO::disable_connecting ();
1597 Stateful::save_extra_xml (node);
1599 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1600 load_options (*child);
1601 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1602 load_options (*child);
1604 error << _("Session: XML state has no options section") << endmsg;
1607 if (version >= 3000) {
1608 if ((child = find_named_node (node, "Metadata")) == 0) {
1609 warning << _("Session: XML state has no metadata section") << endmsg;
1610 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1615 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1616 _speakers->set_state (*child, version);
1619 if ((child = find_named_node (node, "Sources")) == 0) {
1620 error << _("Session: XML state has no sources section") << endmsg;
1622 } else if (load_sources (*child)) {
1626 if ((child = find_named_node (node, "TempoMap")) == 0) {
1627 error << _("Session: XML state has no Tempo Map section") << endmsg;
1629 } else if (_tempo_map->set_state (*child, version)) {
1633 if ((child = find_named_node (node, "Locations")) == 0) {
1634 error << _("Session: XML state has no locations section") << endmsg;
1636 } else if (_locations->set_state (*child, version)) {
1640 locations_changed ();
1642 if (_session_range_location) {
1643 AudioFileSource::set_header_position_offset (_session_range_location->start());
1646 if ((child = find_named_node (node, "Regions")) == 0) {
1647 error << _("Session: XML state has no Regions section") << endmsg;
1649 } else if (load_regions (*child)) {
1653 if ((child = find_named_node (node, "Playlists")) == 0) {
1654 error << _("Session: XML state has no playlists section") << endmsg;
1656 } else if (_playlists->load (*this, *child)) {
1660 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1662 } else if (_playlists->load_unused (*this, *child)) {
1666 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1667 if (load_compounds (*child)) {
1672 if (version >= 3000) {
1673 if ((child = find_named_node (node, "Bundles")) == 0) {
1674 warning << _("Session: XML state has no bundles section") << endmsg;
1677 /* We can't load Bundles yet as they need to be able
1678 * to convert from port names to Port objects, which can't happen until
1680 _bundle_xml_node = new XMLNode (*child);
1684 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1685 _vca_manager->set_state (*child, version);
1688 if (version < 3000) {
1689 if ((child = find_named_node (node, "DiskStreams"))) {
1690 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1691 if ((*n)->name() == "AudioDiskstream" || (*n)->name() == "DiskStream") {
1692 std::string diskstream_id;
1693 std::string playlist_name;
1694 if ((*n)->get_property ("playlist", playlist_name) && (*n)->get_property ("id", diskstream_id)) {
1695 _diskstreams_2X [PBD::ID(diskstream_id)] = playlist_name;
1702 if ((child = find_named_node (node, "Routes")) == 0) {
1703 error << _("Session: XML state has no routes section") << endmsg;
1705 } else if (load_routes (*child, version)) {
1709 /* Now that we Tracks have been loaded and playlists are assigned */
1710 _playlists->update_tracking ();
1712 _diskstreams_2X.clear ();
1714 /* Now that we have Routes and masters loaded, connect them if appropriate */
1716 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1718 if (version >= 3000) {
1720 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1721 error << _("Session: XML state has no route groups section") << endmsg;
1723 } else if (load_route_groups (*child, version)) {
1727 } else if (version < 3000) {
1729 if ((child = find_named_node (node, "EditGroups")) == 0) {
1730 error << _("Session: XML state has no edit groups section") << endmsg;
1732 } else if (load_route_groups (*child, version)) {
1736 if ((child = find_named_node (node, "MixGroups")) == 0) {
1737 error << _("Session: XML state has no mix groups section") << endmsg;
1739 } else if (load_route_groups (*child, version)) {
1744 if ((child = find_named_node (node, "Click")) == 0) {
1745 warning << _("Session: XML state has no click section") << endmsg;
1746 } else if (_click_io) {
1747 setup_click_state (&node);
1750 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1751 ControlProtocolManager::instance().set_state (*child, 1 /* here: session-specific state */);
1754 if ((child = find_named_node (node, "Script"))) {
1755 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1756 if (!(*n)->is_content ()) { continue; }
1758 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1760 Glib::Threads::Mutex::Lock lm (lua_lock);
1761 (*_lua_load)(std::string ((const char*)buf, size));
1762 } catch (luabridge::LuaException const& e) {
1763 cerr << "LuaException:" << e.what () << endl;
1769 if ((child = find_named_node (node, X_("Selection")))) {
1770 _selection->set_state (*child, version);
1773 update_route_record_state ();
1775 /* here beginneth the second phase ... */
1776 set_snapshot_name (_current_snapshot_name);
1778 StateReady (); /* EMIT SIGNAL */
1791 Session::load_routes (const XMLNode& node, int version)
1794 XMLNodeConstIterator niter;
1795 RouteList new_routes;
1797 nlist = node.children();
1801 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1803 boost::shared_ptr<Route> route;
1805 if (version < 3000) {
1806 route = XMLRouteFactory_2X (**niter, version);
1807 } else if (version < 5000) {
1808 route = XMLRouteFactory_3X (**niter, version);
1810 route = XMLRouteFactory (**niter, version);
1814 error << _("Session: cannot create Route from XML description.") << endmsg;
1818 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1820 new_routes.push_back (route);
1823 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1825 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1827 BootMessage (_("Finished adding tracks/busses"));
1832 boost::shared_ptr<Route>
1833 Session::XMLRouteFactory (const XMLNode& node, int version)
1835 boost::shared_ptr<Route> ret;
1837 if (node.name() != "Route") {
1841 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1844 pl_prop = node.property (X_("midi-playlist"));
1847 DataType type = DataType::AUDIO;
1848 node.get_property("default-type", type);
1850 assert (type != DataType::NIL);
1854 /* has at least 1 playlist, therefore a track ... */
1856 boost::shared_ptr<Track> track;
1858 if (type == DataType::AUDIO) {
1859 track.reset (new AudioTrack (*this, string())); // name will be reset from XML in ::set_state() below
1861 track.reset (new MidiTrack (*this, string())); // name will be reset from XML in ::set_state() below
1864 if (track->init()) {
1868 if (track->set_state (node, version)) {
1872 BOOST_MARK_TRACK (track);
1876 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1877 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1880 if (r->init () == 0 && r->set_state (node, version) == 0) {
1881 BOOST_MARK_ROUTE (r);
1889 boost::shared_ptr<Route>
1890 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1892 boost::shared_ptr<Route> ret;
1894 if (node.name() != "Route") {
1898 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1900 DataType type = DataType::AUDIO;
1901 node.get_property("default-type", type);
1903 assert (type != DataType::NIL);
1907 boost::shared_ptr<Track> track;
1909 if (type == DataType::AUDIO) {
1910 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1912 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1915 if (track->init()) {
1919 if (track->set_state (node, version)) {
1923 BOOST_MARK_TRACK (track);
1927 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1928 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1930 if (r->init () == 0 && r->set_state (node, version) == 0) {
1931 BOOST_MARK_ROUTE (r);
1939 boost::shared_ptr<Route>
1940 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1942 boost::shared_ptr<Route> ret;
1944 if (node.name() != "Route") {
1948 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1950 ds_prop = node.property (X_("diskstream"));
1953 DataType type = DataType::AUDIO;
1954 node.get_property("default-type", type);
1956 assert (type != DataType::NIL);
1960 PBD::ID ds_id (ds_prop->value ());
1961 std::string playlist_name = _diskstreams_2X[ds_id];
1963 boost::shared_ptr<Playlist> pl = playlists()->by_name (playlist_name);
1965 if (playlist_name.empty () || !pl) {
1966 warning << string_compose (_("Could not find diskstream for diskream-id: '%1', playlist: '%2'"), ds_prop->value (), playlist_name) << endmsg;
1969 boost::shared_ptr<Track> track;
1971 if (type == DataType::AUDIO) {
1972 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1974 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1977 if (track->init()) {
1982 track->use_playlist (DataType::AUDIO, pl);
1985 if (track->set_state (node, version)) {
1990 pl->set_orig_track_id (track->id());
1991 playlists()->update_orig_2X (ds_id, track->id());
1994 BOOST_MARK_TRACK (track);
1998 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1999 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
2001 if (r->init () == 0 && r->set_state (node, version) == 0) {
2002 BOOST_MARK_ROUTE (r);
2011 Session::load_regions (const XMLNode& node)
2014 XMLNodeConstIterator niter;
2015 boost::shared_ptr<Region> region;
2017 nlist = node.children();
2021 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2022 if ((region = XMLRegionFactory (**niter, false)) == 0) {
2023 error << _("Session: cannot create Region from XML description.");
2024 XMLProperty const * name = (**niter).property("name");
2027 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
2038 Session::load_compounds (const XMLNode& node)
2040 XMLNodeList calist = node.children();
2041 XMLNodeConstIterator caiter;
2042 XMLProperty const * caprop;
2044 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
2045 XMLNode* ca = *caiter;
2049 if ((caprop = ca->property (X_("original"))) == 0) {
2052 orig_id = caprop->value();
2054 if ((caprop = ca->property (X_("copy"))) == 0) {
2057 copy_id = caprop->value();
2059 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2060 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2062 if (!orig || !copy) {
2063 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2069 RegionFactory::add_compound_association (orig, copy);
2076 Session::load_nested_sources (const XMLNode& node)
2079 XMLNodeConstIterator niter;
2081 nlist = node.children();
2083 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2084 if ((*niter)->name() == "Source") {
2086 /* it may already exist, so don't recreate it unnecessarily
2089 XMLProperty const * prop = (*niter)->property (X_("id"));
2091 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2095 ID source_id (prop->value());
2097 if (!source_by_id (source_id)) {
2100 SourceFactory::create (*this, **niter, true);
2102 catch (failed_constructor& err) {
2103 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2110 boost::shared_ptr<Region>
2111 Session::XMLRegionFactory (const XMLNode& node, bool full)
2113 XMLProperty const * type = node.property("type");
2117 const XMLNodeList& nlist = node.children();
2119 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2120 XMLNode *child = (*niter);
2121 if (child->name() == "NestedSource") {
2122 load_nested_sources (*child);
2126 if (!type || type->value() == "audio") {
2127 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2128 } else if (type->value() == "midi") {
2129 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2132 } catch (failed_constructor& err) {
2133 return boost::shared_ptr<Region> ();
2136 return boost::shared_ptr<Region> ();
2139 boost::shared_ptr<AudioRegion>
2140 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2142 XMLProperty const * prop;
2143 boost::shared_ptr<Source> source;
2144 boost::shared_ptr<AudioSource> as;
2146 SourceList master_sources;
2147 uint32_t nchans = 1;
2150 if (node.name() != X_("Region")) {
2151 return boost::shared_ptr<AudioRegion>();
2154 node.get_property (X_("channels"), nchans);
2156 if ((prop = node.property ("name")) == 0) {
2157 cerr << "no name for this region\n";
2161 if ((prop = node.property (X_("source-0"))) == 0) {
2162 if ((prop = node.property ("source")) == 0) {
2163 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2164 return boost::shared_ptr<AudioRegion>();
2168 PBD::ID s_id (prop->value());
2170 if ((source = source_by_id (s_id)) == 0) {
2171 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2172 return boost::shared_ptr<AudioRegion>();
2175 as = boost::dynamic_pointer_cast<AudioSource>(source);
2177 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2178 return boost::shared_ptr<AudioRegion>();
2181 sources.push_back (as);
2183 /* pickup other channels */
2185 for (uint32_t n=1; n < nchans; ++n) {
2186 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2187 if ((prop = node.property (buf)) != 0) {
2189 PBD::ID id2 (prop->value());
2191 if ((source = source_by_id (id2)) == 0) {
2192 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2193 return boost::shared_ptr<AudioRegion>();
2196 as = boost::dynamic_pointer_cast<AudioSource>(source);
2198 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2199 return boost::shared_ptr<AudioRegion>();
2201 sources.push_back (as);
2205 for (uint32_t n = 0; n < nchans; ++n) {
2206 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2207 if ((prop = node.property (buf)) != 0) {
2209 PBD::ID id2 (prop->value());
2211 if ((source = source_by_id (id2)) == 0) {
2212 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2213 return boost::shared_ptr<AudioRegion>();
2216 as = boost::dynamic_pointer_cast<AudioSource>(source);
2218 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2219 return boost::shared_ptr<AudioRegion>();
2221 master_sources.push_back (as);
2226 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2228 /* a final detail: this is the one and only place that we know how long missing files are */
2230 if (region->whole_file()) {
2231 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2232 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2234 sfp->set_length (region->length());
2239 if (!master_sources.empty()) {
2240 if (master_sources.size() != nchans) {
2241 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2243 region->set_master_sources (master_sources);
2251 catch (failed_constructor& err) {
2252 return boost::shared_ptr<AudioRegion>();
2256 boost::shared_ptr<MidiRegion>
2257 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2259 XMLProperty const * prop;
2260 boost::shared_ptr<Source> source;
2261 boost::shared_ptr<MidiSource> ms;
2264 if (node.name() != X_("Region")) {
2265 return boost::shared_ptr<MidiRegion>();
2268 if ((prop = node.property ("name")) == 0) {
2269 cerr << "no name for this region\n";
2273 if ((prop = node.property (X_("source-0"))) == 0) {
2274 if ((prop = node.property ("source")) == 0) {
2275 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2276 return boost::shared_ptr<MidiRegion>();
2280 PBD::ID s_id (prop->value());
2282 if ((source = source_by_id (s_id)) == 0) {
2283 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2284 return boost::shared_ptr<MidiRegion>();
2287 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2289 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2290 return boost::shared_ptr<MidiRegion>();
2293 sources.push_back (ms);
2296 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2297 /* a final detail: this is the one and only place that we know how long missing files are */
2299 if (region->whole_file()) {
2300 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2301 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2303 sfp->set_length (region->length());
2311 catch (failed_constructor& err) {
2312 return boost::shared_ptr<MidiRegion>();
2317 Session::get_sources_as_xml ()
2320 XMLNode* node = new XMLNode (X_("Sources"));
2321 Glib::Threads::Mutex::Lock lm (source_lock);
2323 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2324 node->add_child_nocopy (i->second->get_state());
2331 Session::reset_write_sources (bool mark_write_complete, bool force)
2333 boost::shared_ptr<RouteList> rl = routes.reader();
2334 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2335 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2337 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
2338 tr->reset_write_sources(mark_write_complete, force);
2339 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2345 Session::load_sources (const XMLNode& node)
2348 XMLNodeConstIterator niter;
2349 /* don't need this but it stops some
2350 * versions of gcc complaining about
2351 * discarded return values.
2353 boost::shared_ptr<Source> source;
2355 nlist = node.children();
2358 std::map<std::string, std::string> relocation;
2360 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2361 #ifdef PLATFORM_WINDOWS
2365 XMLNode srcnode (**niter);
2366 bool try_replace_abspath = true;
2370 #ifdef PLATFORM_WINDOWS
2371 // do not show "insert media" popups (files embedded from removable media).
2372 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2374 if ((source = XMLSourceFactory (srcnode)) == 0) {
2375 error << _("Session: cannot create Source from XML description.") << endmsg;
2377 #ifdef PLATFORM_WINDOWS
2378 SetErrorMode(old_mode);
2381 } catch (MissingSource& err) {
2382 #ifdef PLATFORM_WINDOWS
2383 SetErrorMode(old_mode);
2386 /* try previous abs path replacements first */
2387 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2388 std::string dir = Glib::path_get_dirname (err.path);
2389 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2390 if (rl != relocation.end ()) {
2391 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2392 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2393 srcnode.set_property ("origin", newpath);
2394 try_replace_abspath = false;
2401 _missing_file_replacement = "";
2403 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2404 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2405 PROGRAM_NAME) << endmsg;
2409 if (!no_questions_about_missing_files) {
2410 user_choice = MissingFile (this, err.path, err.type).value_or (-1);
2415 switch (user_choice) {
2417 /* user added a new search location
2418 * or selected a new absolute path,
2420 if (Glib::path_is_absolute (err.path)) {
2421 if (!_missing_file_replacement.empty ()) {
2422 /* replace origin, in XML */
2423 std::string newpath = Glib::build_filename (
2424 _missing_file_replacement, Glib::path_get_basename (err.path));
2425 srcnode.set_property ("origin", newpath);
2426 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2427 _missing_file_replacement = "";
2434 /* user asked to quit the entire session load */
2438 no_questions_about_missing_files = true;
2442 no_questions_about_missing_files = true;
2449 case DataType::AUDIO:
2450 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2453 case DataType::MIDI:
2454 /* The MIDI file is actually missing so
2455 * just create a new one in the same
2456 * location. Do not announce its
2460 if (!Glib::path_is_absolute (err.path)) {
2461 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2463 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2468 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2469 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2470 /* reset ID to match the missing one */
2471 source->set_id (**niter);
2472 /* Now we can announce it */
2473 SourceFactory::SourceCreated (source);
2484 boost::shared_ptr<Source>
2485 Session::XMLSourceFactory (const XMLNode& node)
2487 if (node.name() != "Source") {
2488 return boost::shared_ptr<Source>();
2492 /* note: do peak building in another thread when loading session state */
2493 return SourceFactory::create (*this, node, true);
2496 catch (failed_constructor& err) {
2497 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2498 return boost::shared_ptr<Source>();
2503 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2505 if (cannot_save () || template_name.empty ()) {
2509 bool absolute_path = Glib::path_is_absolute (template_name);
2511 /* directory to put the template in */
2512 std::string template_dir_path;
2514 if (!absolute_path) {
2515 std::string user_template_dir(user_template_directory());
2517 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2518 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2519 user_template_dir, g_strerror (errno)) << endmsg;
2523 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2525 template_dir_path = template_name;
2528 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2529 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2530 template_dir_path) << endmsg;
2534 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2535 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2536 template_dir_path, g_strerror (errno)) << endmsg;
2541 std::string template_file_path;
2543 if (absolute_path) {
2544 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2546 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2549 SessionSaveUnderway (); /* EMIT SIGNAL */
2554 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2555 root = &get_template ();
2558 root->remove_nodes_and_delete (X_("description"));
2560 if (!description.empty()) {
2561 XMLNode* desc = new XMLNode (X_("description"));
2562 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2563 desc->add_child_nocopy (*desc_cont);
2565 root->add_child_nocopy (*desc);
2568 tree.set_root (root);
2570 if (!tree.write (template_file_path)) {
2571 error << _("template not saved") << endmsg;
2575 store_recent_templates (template_file_path);
2581 Session::refresh_disk_space ()
2583 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2585 Glib::Threads::Mutex::Lock lm (space_lock);
2587 /* get freespace on every FS that is part of the session path */
2589 _total_free_4k_blocks = 0;
2590 _total_free_4k_blocks_uncertain = false;
2592 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2593 #if defined(__NetBSD__)
2594 struct statvfs statfsbuf;
2596 statvfs (i->path.c_str(), &statfsbuf);
2598 struct statfs statfsbuf;
2600 statfs (i->path.c_str(), &statfsbuf);
2602 double const scale = statfsbuf.f_bsize / 4096.0;
2604 /* See if this filesystem is read-only */
2605 struct statvfs statvfsbuf;
2606 statvfs (i->path.c_str(), &statvfsbuf);
2608 /* f_bavail can be 0 if it is undefined for whatever
2609 filesystem we are looking at; Samba shares mounted
2610 via GVFS are an example of this.
2612 if (statfsbuf.f_bavail == 0) {
2613 /* block count unknown */
2615 i->blocks_unknown = true;
2616 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2617 /* read-only filesystem */
2619 i->blocks_unknown = false;
2621 /* read/write filesystem with known space */
2622 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2623 i->blocks_unknown = false;
2626 _total_free_4k_blocks += i->blocks;
2627 if (i->blocks_unknown) {
2628 _total_free_4k_blocks_uncertain = true;
2631 #elif defined PLATFORM_WINDOWS
2632 vector<string> scanned_volumes;
2633 vector<string>::iterator j;
2634 vector<space_and_path>::iterator i;
2635 DWORD nSectorsPerCluster, nBytesPerSector,
2636 nFreeClusters, nTotalClusters;
2640 _total_free_4k_blocks = 0;
2642 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2643 strncpy (disk_drive, (*i).path.c_str(), 3);
2647 volume_found = false;
2648 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2650 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2651 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2652 i->blocks = (uint32_t)(nFreeBytes / 4096);
2654 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2655 if (0 == j->compare(disk_drive)) {
2656 volume_found = true;
2661 if (!volume_found) {
2662 scanned_volumes.push_back(disk_drive);
2663 _total_free_4k_blocks += i->blocks;
2668 if (0 == _total_free_4k_blocks) {
2669 strncpy (disk_drive, path().c_str(), 3);
2672 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2674 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2675 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2676 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2683 Session::get_best_session_directory_for_new_audio ()
2685 vector<space_and_path>::iterator i;
2686 string result = _session_dir->root_path();
2688 /* handle common case without system calls */
2690 if (session_dirs.size() == 1) {
2694 /* OK, here's the algorithm we're following here:
2696 We want to select which directory to use for
2697 the next file source to be created. Ideally,
2698 we'd like to use a round-robin process so as to
2699 get maximum performance benefits from splitting
2700 the files across multiple disks.
2702 However, in situations without much diskspace, an
2703 RR approach may end up filling up a filesystem
2704 with new files while others still have space.
2705 Its therefore important to pay some attention to
2706 the freespace in the filesystem holding each
2707 directory as well. However, if we did that by
2708 itself, we'd keep creating new files in the file
2709 system with the most space until it was as full
2710 as all others, thus negating any performance
2711 benefits of this RAID-1 like approach.
2713 So, we use a user-configurable space threshold. If
2714 there are at least 2 filesystems with more than this
2715 much space available, we use RR selection between them.
2716 If not, then we pick the filesystem with the most space.
2718 This gets a good balance between the two
2722 refresh_disk_space ();
2724 int free_enough = 0;
2726 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2727 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2732 if (free_enough >= 2) {
2733 /* use RR selection process, ensuring that the one
2737 i = last_rr_session_dir;
2740 if (++i == session_dirs.end()) {
2741 i = session_dirs.begin();
2744 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2745 SessionDirectory sdir(i->path);
2746 if (sdir.create ()) {
2748 last_rr_session_dir = i;
2753 } while (i != last_rr_session_dir);
2757 /* pick FS with the most freespace (and that
2758 seems to actually work ...)
2761 vector<space_and_path> sorted;
2762 space_and_path_ascending_cmp cmp;
2764 sorted = session_dirs;
2765 sort (sorted.begin(), sorted.end(), cmp);
2767 for (i = sorted.begin(); i != sorted.end(); ++i) {
2768 SessionDirectory sdir(i->path);
2769 if (sdir.create ()) {
2771 last_rr_session_dir = i;
2781 Session::automation_dir () const
2783 return Glib::build_filename (_path, automation_dir_name);
2787 Session::analysis_dir () const
2789 return Glib::build_filename (_path, analysis_dir_name);
2793 Session::plugins_dir () const
2795 return Glib::build_filename (_path, plugins_dir_name);
2799 Session::externals_dir () const
2801 return Glib::build_filename (_path, externals_dir_name);
2805 Session::load_bundles (XMLNode const & node)
2807 XMLNodeList nlist = node.children();
2808 XMLNodeConstIterator niter;
2812 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2813 if ((*niter)->name() == "InputBundle") {
2814 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2815 } else if ((*niter)->name() == "OutputBundle") {
2816 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2818 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2827 Session::load_route_groups (const XMLNode& node, int version)
2829 XMLNodeList nlist = node.children();
2830 XMLNodeConstIterator niter;
2834 if (version >= 3000) {
2836 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2837 if ((*niter)->name() == "RouteGroup") {
2838 RouteGroup* rg = new RouteGroup (*this, "");
2839 add_route_group (rg);
2840 rg->set_state (**niter, version);
2844 } else if (version < 3000) {
2846 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2847 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2848 RouteGroup* rg = new RouteGroup (*this, "");
2849 add_route_group (rg);
2850 rg->set_state (**niter, version);
2859 state_file_filter (const string &str, void* /*arg*/)
2861 return (str.length() > strlen(statefile_suffix) &&
2862 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2866 remove_end(string state)
2868 string statename(state);
2870 string::size_type start,end;
2871 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2872 statename = statename.substr (start+1);
2875 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2876 end = statename.length();
2879 return string(statename.substr (0, end));
2883 Session::possible_states (string path)
2885 vector<string> states;
2886 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2888 transform(states.begin(), states.end(), states.begin(), remove_end);
2890 sort (states.begin(), states.end());
2896 Session::possible_states () const
2898 return possible_states(_path);
2902 Session::new_route_group (const std::string& name)
2904 RouteGroup* rg = NULL;
2906 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2907 if ((*i)->name () == name) {
2914 rg = new RouteGroup (*this, name);
2915 add_route_group (rg);
2921 Session::add_route_group (RouteGroup* g)
2923 _route_groups.push_back (g);
2924 route_group_added (g); /* EMIT SIGNAL */
2926 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2927 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2928 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2934 Session::remove_route_group (RouteGroup& rg)
2936 list<RouteGroup*>::iterator i;
2938 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2939 _route_groups.erase (i);
2942 route_group_removed (); /* EMIT SIGNAL */
2946 /** Set a new order for our route groups, without adding or removing any.
2947 * @param groups Route group list in the new order.
2950 Session::reorder_route_groups (list<RouteGroup*> groups)
2952 _route_groups = groups;
2954 route_groups_reordered (); /* EMIT SIGNAL */
2960 Session::route_group_by_name (string name)
2962 list<RouteGroup *>::iterator i;
2964 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2965 if ((*i)->name() == name) {
2973 Session::all_route_group() const
2975 return *_all_route_group;
2979 Session::add_commands (vector<Command*> const & cmds)
2981 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2987 Session::add_command (Command* const cmd)
2989 assert (_current_trans);
2990 DEBUG_UNDO_HISTORY (
2991 string_compose ("Current Undo Transaction %1, adding command: %2",
2992 _current_trans->name (),
2994 _current_trans->add_command (cmd);
2997 PBD::StatefulDiffCommand*
2998 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
3000 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
3006 Session::begin_reversible_command (const string& name)
3008 begin_reversible_command (g_quark_from_string (name.c_str ()));
3011 /** Begin a reversible command using a GQuark to identify it.
3012 * begin_reversible_command() and commit_reversible_command() calls may be nested,
3013 * but there must be as many begin...()s as there are commit...()s.
3016 Session::begin_reversible_command (GQuark q)
3018 /* If nested begin/commit pairs are used, we create just one UndoTransaction
3019 to hold all the commands that are committed. This keeps the order of
3020 commands correct in the history.
3023 if (_current_trans == 0) {
3024 DEBUG_UNDO_HISTORY (string_compose (
3025 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
3027 /* start a new transaction */
3028 assert (_current_trans_quarks.empty ());
3029 _current_trans = new UndoTransaction();
3030 _current_trans->set_name (g_quark_to_string (q));
3032 DEBUG_UNDO_HISTORY (
3033 string_compose ("Begin Reversible Command, current transaction: %1",
3034 _current_trans->name ()));
3037 _current_trans_quarks.push_front (q);
3041 Session::abort_reversible_command ()
3043 if (_current_trans != 0) {
3044 DEBUG_UNDO_HISTORY (
3045 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
3046 _current_trans->clear();
3047 delete _current_trans;
3049 _current_trans_quarks.clear();
3054 Session::commit_reversible_command (Command *cmd)
3056 assert (_current_trans);
3057 assert (!_current_trans_quarks.empty ());
3062 DEBUG_UNDO_HISTORY (
3063 string_compose ("Current Undo Transaction %1, adding command: %2",
3064 _current_trans->name (),
3066 _current_trans->add_command (cmd);
3069 DEBUG_UNDO_HISTORY (
3070 string_compose ("Commit Reversible Command, current transaction: %1",
3071 _current_trans->name ()));
3073 _current_trans_quarks.pop_front ();
3075 if (!_current_trans_quarks.empty ()) {
3076 DEBUG_UNDO_HISTORY (
3077 string_compose ("Commit Reversible Command, transaction is not "
3078 "top-level, current transaction: %1",
3079 _current_trans->name ()));
3080 /* the transaction we're committing is not the top-level one */
3084 if (_current_trans->empty()) {
3085 /* no commands were added to the transaction, so just get rid of it */
3086 DEBUG_UNDO_HISTORY (
3087 string_compose ("Commit Reversible Command, No commands were "
3088 "added to current transaction: %1",
3089 _current_trans->name ()));
3090 delete _current_trans;
3095 gettimeofday (&now, 0);
3096 _current_trans->set_timestamp (now);
3098 _history.add (_current_trans);
3103 accept_all_audio_files (const string& path, void* /*arg*/)
3105 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3109 if (!AudioFileSource::safe_audio_file_extension (path)) {
3117 accept_all_midi_files (const string& path, void* /*arg*/)
3119 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3123 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3124 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3125 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3129 accept_all_state_files (const string& path, void* /*arg*/)
3131 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3135 std::string const statefile_ext (statefile_suffix);
3136 if (path.length() >= statefile_ext.length()) {
3137 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3144 Session::find_all_sources (string path, set<string>& result)
3149 if (!tree.read (path)) {
3153 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3158 XMLNodeConstIterator niter;
3160 nlist = node->children();
3164 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3166 XMLProperty const * prop;
3168 if ((prop = (*niter)->property (X_("type"))) == 0) {
3172 DataType type (prop->value());
3174 if ((prop = (*niter)->property (X_("name"))) == 0) {
3178 if (Glib::path_is_absolute (prop->value())) {
3179 /* external file, ignore */
3187 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3188 result.insert (found_path);
3196 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3198 vector<string> state_files;
3200 string this_snapshot_path;
3206 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3207 ripped = ripped.substr (0, ripped.length() - 1);
3210 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3212 if (state_files.empty()) {
3217 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3218 this_snapshot_path += statefile_suffix;
3220 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3222 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3224 if (exclude_this_snapshot && *i == this_snapshot_path) {
3225 cerr << "\texcluded\n";
3230 if (find_all_sources (*i, result) < 0) {
3238 struct RegionCounter {
3239 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3240 AudioSourceList::iterator iter;
3241 boost::shared_ptr<Region> region;
3244 RegionCounter() : count (0) {}
3248 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3250 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3251 return r.value_or (1);
3255 Session::cleanup_regions ()
3257 bool removed = false;
3258 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3260 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3262 uint32_t used = _playlists->region_use_count (i->second);
3264 if (used == 0 && !i->second->automatic ()) {
3265 boost::weak_ptr<Region> w = i->second;
3268 RegionFactory::map_remove (w);
3275 // re-check to remove parent references of compound regions
3276 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3277 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3281 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3282 if (0 == _playlists->region_use_count (i->second)) {
3283 boost::weak_ptr<Region> w = i->second;
3285 RegionFactory::map_remove (w);
3292 /* dump the history list */
3299 Session::can_cleanup_peakfiles () const
3301 if (deletion_in_progress()) {
3304 if (!_writable || cannot_save ()) {
3305 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3308 if (record_status() == Recording) {
3309 error << _("Cannot cleanup peak-files while recording") << endmsg;
3316 Session::cleanup_peakfiles ()
3318 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3323 assert (can_cleanup_peakfiles ());
3324 assert (!peaks_cleanup_in_progres());
3326 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3328 int timeout = 5000; // 5 seconds
3329 while (!SourceFactory::files_with_peaks.empty()) {
3330 Glib::usleep (1000);
3331 if (--timeout < 0) {
3332 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3333 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3338 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3339 boost::shared_ptr<AudioSource> as;
3340 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3341 as->close_peakfile();
3345 PBD::clear_directory (session_directory().peak_path());
3347 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3349 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3350 boost::shared_ptr<AudioSource> as;
3351 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3352 SourceFactory::setup_peakfile(as, true);
3359 Session::cleanup_sources (CleanupReport& rep)
3361 // FIXME: needs adaptation to midi
3363 vector<boost::shared_ptr<Source> > dead_sources;
3366 vector<string> candidates;
3367 vector<string> unused;
3368 set<string> sources_used_by_all_snapshots;
3375 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3377 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
3379 /* this is mostly for windows which doesn't allow file
3380 * renaming if the file is in use. But we don't special
3381 * case it because we need to know if this causes
3382 * problems, and the easiest way to notice that is to
3383 * keep it in place for all platforms.
3386 request_stop (false);
3388 _butler->wait_until_finished ();
3390 /* consider deleting all unused playlists */
3392 if (_playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3397 /* sync the "all regions" property of each playlist with its current state */
3399 _playlists->sync_all_regions_with_regions ();
3401 /* find all un-used sources */
3406 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3408 SourceMap::iterator tmp;
3413 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3417 if (!i->second->used() && (i->second->length(i->second->natural_position()) > 0)) {
3418 dead_sources.push_back (i->second);
3419 i->second->drop_references ();
3425 /* build a list of all the possible audio directories for the session */
3427 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3428 SessionDirectory sdir ((*i).path);
3429 asp += sdir.sound_path();
3431 audio_path += asp.to_string();
3434 /* build a list of all the possible midi directories for the session */
3436 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3437 SessionDirectory sdir ((*i).path);
3438 msp += sdir.midi_path();
3440 midi_path += msp.to_string();
3442 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3443 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3445 /* add sources from all other snapshots as "used", but don't use this
3446 snapshot because the state file on disk still references sources we
3447 may have already dropped.
3450 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3452 /* Although the region factory has a list of all regions ever created
3453 * for this session, we're only interested in regions actually in
3454 * playlists right now. So merge all playlist regions lists together.
3456 * This will include the playlists used within compound regions.
3459 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3461 /* add our current source list
3464 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3465 boost::shared_ptr<FileSource> fs;
3466 SourceMap::iterator tmp = i;
3469 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3475 /* this is mostly for windows which doesn't allow file
3476 * renaming if the file is in use. But we do not special
3477 * case it because we need to know if this causes
3478 * problems, and the easiest way to notice that is to
3479 * keep it in place for all platforms.
3484 if (!fs->is_stub()) {
3486 /* Note that we're checking a list of all
3487 * sources across all snapshots with the list
3488 * of sources used by this snapshot.
3491 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3492 /* this source is in use by this snapshot */
3493 sources_used_by_all_snapshots.insert (fs->path());
3494 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3496 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3497 /* this source is NOT in use by this snapshot */
3499 /* remove all related regions from RegionFactory master list */
3501 RegionFactory::remove_regions_using_source (i->second);
3503 /* remove from our current source list
3504 * also. We may not remove it from
3505 * disk, because it may be used by
3506 * other snapshots, but it isn't used inside this
3507 * snapshot anymore, so we don't need a
3518 /* now check each candidate source to see if it exists in the list of
3519 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3522 cerr << "Candidates: " << candidates.size() << endl;
3523 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3525 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3530 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3532 tmppath1 = canonical_path (spath);
3533 tmppath2 = canonical_path ((*i));
3535 cerr << "\t => " << tmppath2 << endl;
3537 if (tmppath1 == tmppath2) {
3544 unused.push_back (spath);
3548 cerr << "Actually unused: " << unused.size() << endl;
3550 if (unused.empty()) {
3556 /* now try to move all unused files into the "dead" directory(ies) */
3558 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3563 /* don't move the file across filesystems, just
3564 * stick it in the `dead_dir_name' directory
3565 * on whichever filesystem it was already on.
3568 if ((*x).find ("/sounds/") != string::npos) {
3570 /* old school, go up 1 level */
3572 newpath = Glib::path_get_dirname (*x); // "sounds"
3573 newpath = Glib::path_get_dirname (newpath); // "session-name"
3577 /* new school, go up 4 levels */
3579 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3580 newpath = Glib::path_get_dirname (newpath); // "session-name"
3581 newpath = Glib::path_get_dirname (newpath); // "interchange"
3582 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3585 newpath = Glib::build_filename (newpath, dead_dir_name);
3587 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3588 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3592 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3594 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3596 /* the new path already exists, try versioning */
3598 char buf[PATH_MAX+1];
3602 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3605 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3606 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3610 if (version == 999) {
3611 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3615 newpath = newpath_v;
3620 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3621 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3622 newpath, g_strerror (errno)) << endmsg;
3626 /* see if there an easy to find peakfile for this file, and remove it. */
3628 string base = Glib::path_get_basename (*x);
3629 base += "%A"; /* this is what we add for the channel suffix of all native files,
3630 * or for the first channel of embedded files. it will miss
3631 * some peakfiles for other channels
3633 string peakpath = construct_peak_filepath (base);
3635 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3636 if (::g_unlink (peakpath.c_str ()) != 0) {
3637 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3638 g_strerror (errno)) << endmsg;
3639 /* try to back out */
3640 ::g_rename (newpath.c_str (), _path.c_str ());
3645 rep.paths.push_back (*x);
3646 rep.space += statbuf.st_size;
3649 /* dump the history list */
3653 /* save state so we don't end up a session file
3654 * referring to non-existent sources.
3661 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
3667 Session::cleanup_trash_sources (CleanupReport& rep)
3669 // FIXME: needs adaptation for MIDI
3671 vector<space_and_path>::iterator i;
3677 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3679 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3681 clear_directory (dead_dir, &rep.space, &rep.paths);
3688 Session::set_dirty ()
3690 /* return early if there's nothing to do */
3695 /* never mark session dirty during loading */
3696 if (loading () || deletion_in_progress ()) {
3700 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3701 DirtyChanged(); /* EMIT SIGNAL */
3705 Session::set_clean ()
3707 bool was_dirty = dirty();
3709 _state_of_the_state = Clean;
3712 DirtyChanged(); /* EMIT SIGNAL */
3717 Session::unset_dirty (bool emit_dirty_changed)
3719 bool was_dirty = dirty();
3721 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Dirty));
3723 if (was_dirty && emit_dirty_changed) {
3724 DirtyChanged (); /* EMIT SIGNAL */
3729 Session::set_deletion_in_progress ()
3731 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3735 Session::clear_deletion_in_progress ()
3737 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3741 Session::add_controllable (boost::shared_ptr<Controllable> c)
3743 /* this adds a controllable to the list managed by the Session.
3744 this is a subset of those managed by the Controllable class
3745 itself, and represents the only ones whose state will be saved
3746 as part of the session.
3749 Glib::Threads::Mutex::Lock lm (controllables_lock);
3750 controllables.insert (c);
3753 boost::shared_ptr<Controllable>
3754 Session::controllable_by_id (const PBD::ID& id)
3756 Glib::Threads::Mutex::Lock lm (controllables_lock);
3758 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3759 if ((*i)->id() == id) {
3764 return boost::shared_ptr<Controllable>();
3767 boost::shared_ptr<AutomationControl>
3768 Session::automation_control_by_id (const PBD::ID& id)
3770 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3774 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3777 Stateful::add_instant_xml (node, _path);
3780 if (write_to_config) {
3781 Config->add_instant_xml (node);
3786 Session::instant_xml (const string& node_name)
3788 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3789 if (get_disable_all_loaded_plugins ()) {
3793 return Stateful::instant_xml (node_name, _path);
3797 Session::save_history (string snapshot_name)
3805 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3806 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3810 if (snapshot_name.empty()) {
3811 snapshot_name = _current_snapshot_name;
3814 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3815 const string backup_filename = history_filename + backup_suffix;
3816 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3817 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3819 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3820 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3821 error << _("could not backup old history file, current history not saved") << endmsg;
3826 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3828 if (!tree.write (xml_path))
3830 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3832 if (g_remove (xml_path.c_str()) != 0) {
3833 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3834 xml_path, g_strerror (errno)) << endmsg;
3836 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3837 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3838 backup_path, g_strerror (errno)) << endmsg;
3848 Session::restore_history (string snapshot_name)
3852 if (snapshot_name.empty()) {
3853 snapshot_name = _current_snapshot_name;
3856 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3857 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3859 info << "Loading history from " << xml_path << endmsg;
3861 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3862 info << string_compose (_("%1: no history file \"%2\" for this session."),
3863 _name, xml_path) << endmsg;
3867 if (!tree.read (xml_path)) {
3868 error << string_compose (_("Could not understand session history file \"%1\""),
3869 xml_path) << endmsg;
3876 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3884 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3885 !t->get_property ("tv-usec", tv_usec)) {
3889 UndoTransaction* ut = new UndoTransaction ();
3890 ut->set_name (name);
3894 tv.tv_usec = tv_usec;
3895 ut->set_timestamp(tv);
3897 for (XMLNodeConstIterator child_it = t->children().begin();
3898 child_it != t->children().end(); child_it++)
3900 XMLNode *n = *child_it;
3903 if (n->name() == "MementoCommand" ||
3904 n->name() == "MementoUndoCommand" ||
3905 n->name() == "MementoRedoCommand") {
3907 if ((c = memento_command_factory(n))) {
3911 } else if (n->name() == "NoteDiffCommand") {
3912 PBD::ID id (n->property("midi-source")->value());
3913 boost::shared_ptr<MidiSource> midi_source =
3914 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3916 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3918 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3921 } else if (n->name() == "SysExDiffCommand") {
3923 PBD::ID id (n->property("midi-source")->value());
3924 boost::shared_ptr<MidiSource> midi_source =
3925 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3927 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3929 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3932 } else if (n->name() == "PatchChangeDiffCommand") {
3934 PBD::ID id (n->property("midi-source")->value());
3935 boost::shared_ptr<MidiSource> midi_source =
3936 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3938 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3940 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3943 } else if (n->name() == "StatefulDiffCommand") {
3944 if ((c = stateful_diff_command_factory (n))) {
3945 ut->add_command (c);
3948 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3959 Session::config_changed (std::string p, bool ours)
3965 if (p == "auto-loop") {
3967 } else if (p == "session-monitoring") {
3969 } else if (p == "auto-input") {
3971 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3972 /* auto-input only makes a difference if we're rolling */
3973 set_track_monitor_input_status (!config.get_auto_input());
3976 } else if (p == "punch-in") {
3980 if ((location = _locations->auto_punch_location()) != 0) {
3982 if (config.get_punch_in ()) {
3983 auto_punch_start_changed (location);
3985 clear_events (SessionEvent::PunchIn);
3989 } else if (p == "punch-out") {
3993 if ((location = _locations->auto_punch_location()) != 0) {
3995 if (config.get_punch_out()) {
3996 auto_punch_end_changed (location);
3998 clear_events (SessionEvent::PunchOut);
4002 } else if (p == "edit-mode") {
4004 Glib::Threads::Mutex::Lock lm (_playlists->lock);
4006 for (SessionPlaylists::List::iterator i = _playlists->playlists.begin(); i != _playlists->playlists.end(); ++i) {
4007 (*i)->set_edit_mode (Config->get_edit_mode ());
4010 } else if (p == "use-video-sync") {
4012 waiting_for_sync_offset = config.get_use_video_sync();
4014 } else if (p == "mmc-control") {
4016 //poke_midi_thread ();
4018 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4020 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4022 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4024 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4026 } else if (p == "midi-control") {
4028 //poke_midi_thread ();
4030 } else if (p == "raid-path") {
4032 setup_raid_path (config.get_raid_path());
4034 } else if (p == "timecode-format") {
4038 } else if (p == "video-pullup") {
4042 } else if (p == "seamless-loop") {
4044 if (play_loop && transport_rolling()) {
4045 // to reset diskstreams etc
4046 request_play_loop (true);
4049 } else if (p == "click-sound") {
4051 setup_click_sounds (1);
4053 } else if (p == "click-emphasis-sound") {
4055 setup_click_sounds (-1);
4057 } else if (p == "clicking") {
4059 if (Config->get_clicking()) {
4060 if (_click_io && click_data) { // don't require emphasis data
4067 } else if (p == "click-record-only") {
4069 _click_rec_only = Config->get_click_record_only();
4071 } else if (p == "click-gain") {
4074 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4077 } else if (p == "send-mtc") {
4079 if (Config->get_send_mtc ()) {
4080 /* mark us ready to send */
4081 next_quarter_frame_to_send = 0;
4084 } else if (p == "send-mmc") {
4086 _mmc->enable_send (Config->get_send_mmc ());
4087 if (Config->get_send_mmc ()) {
4088 /* re-initialize MMC */
4089 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4090 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4093 } else if (p == "jack-time-master") {
4095 engine().reset_timebase ();
4097 } else if (p == "native-file-header-format") {
4099 if (!first_file_header_format_reset) {
4100 reset_native_file_format ();
4103 first_file_header_format_reset = false;
4105 } else if (p == "native-file-data-format") {
4107 if (!first_file_data_format_reset) {
4108 reset_native_file_format ();
4111 first_file_data_format_reset = false;
4113 } else if (p == "external-sync") {
4114 request_sync_source (TransportMasterManager::instance().current());
4115 } else if (p == "denormal-model") {
4117 } else if (p == "history-depth") {
4118 set_history_depth (Config->get_history_depth());
4119 } else if (p == "remote-model") {
4120 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4123 } else if (p == "initial-program-change") {
4125 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4128 buf[0] = MIDI::program; // channel zero by default
4129 buf[1] = (Config->get_initial_program_change() & 0x7f);
4131 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4133 } else if (p == "solo-mute-override") {
4134 // catch_up_on_solo_mute_override ();
4135 } else if (p == "listen-position" || p == "pfl-position") {
4136 listen_position_changed ();
4137 } else if (p == "solo-control-is-listen-control") {
4138 solo_control_mode_changed ();
4139 } else if (p == "solo-mute-gain") {
4140 _solo_cut_control->Changed (true, Controllable::NoGroup);
4141 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4142 last_timecode_valid = false;
4143 } else if (p == "playback-buffer-seconds") {
4144 AudioSource::allocate_working_buffers (sample_rate());
4145 } else if (p == "ltc-sink-port") {
4146 reconnect_ltc_output ();
4147 } else if (p == "timecode-generator-offset") {
4148 ltc_tx_parse_offset();
4149 } else if (p == "auto-return-target-list") {
4151 follow_playhead_priority ();
4153 } else if (p == "use-monitor-bus") {
4154 /* NB. This is always called when constructing a session,
4155 * after restoring session state (if any),
4156 * via post_engine_init() -> Config->map_parameters()
4158 bool want_ms = Config->get_use_monitor_bus();
4159 bool have_ms = _monitor_out ? true : false;
4161 /* When loading an existing session, the config "use-monitor-bus"
4162 * is ignored. Instead the sesion-state (xml) will have added the
4163 * "monitor-route" and restored its state (and connections)
4164 * if the session has a monitor-section.
4165 * Update the config to reflect this.
4167 if (want_ms != have_ms) {
4168 Config->set_use_monitor_bus (have_ms);
4170 MonitorBusAddedOrRemoved (); /* EMIT SIGNAL */
4172 /* Otherwise, Config::set_use_monitor_bus() does
4173 * control the the presence of the monitor-section
4174 * (new sessions, user initiated change)
4176 if (want_ms && !have_ms) {
4177 add_monitor_section ();
4178 } else if (!want_ms && have_ms) {
4179 remove_monitor_section ();
4182 } else if (p == "loop-fade-choice") {
4183 last_loopend = 0; /* force locate to refill buffers with new loop boundary data */
4184 auto_loop_changed (_locations->auto_loop_location());
4191 Session::set_history_depth (uint32_t d)
4193 _history.set_depth (d);
4196 /** Connect things to the MMC object */
4198 Session::setup_midi_machine_control ()
4200 _mmc = new MIDI::MachineControl;
4202 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4203 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4205 if (!async_out || !async_out) {
4209 /* XXXX argh, passing raw pointers back into libmidi++ */
4211 MIDI::Port* mmc_in = async_in.get();
4212 MIDI::Port* mmc_out = async_out.get();
4214 _mmc->set_ports (mmc_in, mmc_out);
4216 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4217 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4218 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4219 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4220 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4221 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4222 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4223 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4224 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4225 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4226 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4227 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4228 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4230 /* also handle MIDI SPP because its so common */
4232 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4233 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4234 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4237 boost::shared_ptr<Controllable>
4238 Session::solo_cut_control() const
4240 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4241 * controls in Ardour that currently get presented to the user in the GUI that require
4242 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4244 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4245 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4248 return _solo_cut_control;
4252 Session::save_snapshot_name (const std::string & n)
4254 /* assure Stateful::_instant_xml is loaded
4255 * add_instant_xml() only adds to existing data and defaults
4256 * to use an empty Tree otherwise
4258 instant_xml ("LastUsedSnapshot");
4260 XMLNode last_used_snapshot ("LastUsedSnapshot");
4261 last_used_snapshot.set_property ("name", n);
4262 add_instant_xml (last_used_snapshot, false);
4266 Session::set_snapshot_name (const std::string & n)
4268 _current_snapshot_name = n;
4269 save_snapshot_name (n);
4273 Session::rename (const std::string& new_name)
4275 string legal_name = legalize_for_path (new_name);
4281 string const old_sources_root = _session_dir->sources_root();
4283 if (!_writable || cannot_save ()) {
4284 error << _("Cannot rename read-only session.") << endmsg;
4285 return 0; // don't show "messed up" warning
4287 if (record_status() == Recording) {
4288 error << _("Cannot rename session while recording") << endmsg;
4289 return 0; // don't show "messed up" warning
4292 StateProtector stp (this);
4297 * interchange subdirectory
4301 * Backup files are left unchanged and not renamed.
4304 /* Windows requires that we close all files before attempting the
4305 * rename. This works on other platforms, but isn't necessary there.
4306 * Leave it in place for all platforms though, since it may help
4307 * catch issues that could arise if the way Source files work ever
4308 * change (since most developers are not using Windows).
4311 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4312 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4318 /* pass one: not 100% safe check that the new directory names don't
4322 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4326 /* this is a stupid hack because Glib::path_get_dirname() is
4327 * lexical-only, and so passing it /a/b/c/ gives a different
4328 * result than passing it /a/b/c ...
4331 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4332 oldstr = oldstr.substr (0, oldstr.length() - 1);
4335 string base = Glib::path_get_dirname (oldstr);
4337 newstr = Glib::build_filename (base, legal_name);
4339 cerr << "Looking for " << newstr << endl;
4341 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4342 cerr << " exists\n";
4351 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4357 /* this is a stupid hack because Glib::path_get_dirname() is
4358 * lexical-only, and so passing it /a/b/c/ gives a different
4359 * result than passing it /a/b/c ...
4362 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4363 oldstr = oldstr.substr (0, oldstr.length() - 1);
4366 string base = Glib::path_get_dirname (oldstr);
4367 newstr = Glib::build_filename (base, legal_name);
4369 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4371 cerr << "Rename " << oldstr << " => " << newstr << endl;
4372 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4373 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4374 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4378 /* Reset path in "session dirs" */
4383 /* reset primary SessionDirectory object */
4386 (*_session_dir) = newstr;
4391 /* now rename directory below session_dir/interchange */
4393 string old_interchange_dir;
4394 string new_interchange_dir;
4396 /* use newstr here because we renamed the path
4397 * (folder/directory) that used to be oldstr to newstr above
4400 v.push_back (newstr);
4401 v.push_back (interchange_dir_name);
4402 v.push_back (Glib::path_get_basename (oldstr));
4404 old_interchange_dir = Glib::build_filename (v);
4407 v.push_back (newstr);
4408 v.push_back (interchange_dir_name);
4409 v.push_back (legal_name);
4411 new_interchange_dir = Glib::build_filename (v);
4413 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4415 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4416 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4417 old_interchange_dir, new_interchange_dir,
4420 error << string_compose (_("renaming %s as %2 failed (%3)"),
4421 old_interchange_dir, new_interchange_dir,
4430 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4431 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4433 cerr << "Rename " << oldstr << " => " << newstr << endl;
4435 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4436 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4437 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4443 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4445 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4446 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4448 cerr << "Rename " << oldstr << " => " << newstr << endl;
4450 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4451 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4452 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4457 /* remove old name from recent sessions */
4458 remove_recent_sessions (_path);
4461 /* update file source paths */
4463 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4464 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4466 string p = fs->path ();
4467 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4469 SourceFactory::setup_peakfile(i->second, true);
4473 set_snapshot_name (new_name);
4478 /* save state again to get everything just right */
4480 save_state (_current_snapshot_name);
4482 /* add to recent sessions */
4484 store_recent_sessions (new_name, _path);
4490 Session::parse_stateful_loading_version (const std::string& version)
4492 if (version.empty ()) {
4493 /* no version implies very old version of Ardour */
4497 if (version.find ('.') != string::npos) {
4498 /* old school version format */
4499 if (version[0] == '2') {
4505 return string_to<int32_t>(version);
4510 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4512 bool found_sr = false;
4513 bool found_data_format = false;
4514 std::string version;
4515 program_version = "";
4517 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4521 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4525 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4528 xmlFreeParserCtxt(ctxt);
4532 xmlNodePtr node = xmlDocGetRootElement(doc);
4535 xmlFreeParserCtxt(ctxt);
4540 /* sample rate & version*/
4543 for (attr = node->properties; attr; attr = attr->next) {
4544 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4545 version = std::string ((char*)attr->children->content);
4547 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4548 sample_rate = atoi ((char*)attr->children->content);
4553 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4557 if ((parse_stateful_loading_version(version) / 1000L) <= 2) {
4558 /* sample-format '0' is implicit */
4559 data_format = FormatFloat;
4560 found_data_format = true;
4563 node = node->children;
4564 while (node != NULL) {
4565 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4566 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4568 program_version = string ((const char*)val);
4569 size_t sep = program_version.find_first_of("-");
4570 if (sep != string::npos) {
4571 program_version = program_version.substr (0, sep);
4576 if (strcmp((const char*) node->name, "Config")) {
4580 for (node = node->children; node; node = node->next) {
4581 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4582 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4584 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4587 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4589 found_data_format = true;
4590 } catch (PBD::unknown_enumeration& e) {}
4600 xmlFreeParserCtxt(ctxt);
4603 return (found_sr && found_data_format) ? 0 : 1;
4607 Session::get_snapshot_from_instant (const std::string& session_dir)
4609 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4611 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4616 if (!tree.read (instant_xml_path)) {
4620 XMLProperty const * prop;
4621 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4622 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4623 return prop->value();
4629 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4630 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4633 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4637 SourcePathMap source_path_map;
4639 boost::shared_ptr<AudioFileSource> afs;
4644 Glib::Threads::Mutex::Lock lm (source_lock);
4646 cerr << " total sources = " << sources.size();
4648 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4649 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4655 if (fs->within_session()) {
4659 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4660 source_path_map[fs->path()].push_back (fs);
4662 SeveralFileSources v;
4664 source_path_map.insert (make_pair (fs->path(), v));
4670 cerr << " fsources = " << total << endl;
4672 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4674 /* tell caller where we are */
4676 string old_path = i->first;
4678 callback (n, total, old_path);
4680 cerr << old_path << endl;
4684 switch (i->second.front()->type()) {
4685 case DataType::AUDIO:
4686 new_path = new_audio_source_path_for_embedded (old_path);
4689 case DataType::MIDI:
4690 /* XXX not implemented yet */
4694 if (new_path.empty()) {
4698 cerr << "Move " << old_path << " => " << new_path << endl;
4700 if (!copy_file (old_path, new_path)) {
4701 cerr << "failed !\n";
4705 /* make sure we stop looking in the external
4706 dir/folder. Remember, this is an all-or-nothing
4707 operations, it doesn't merge just some files.
4709 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4711 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4712 (*f)->set_path (new_path);
4717 save_state ("", false, false);
4723 bool accept_all_files (string const &, void *)
4729 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4731 /* 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.
4736 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4738 // old_path must be in within_session ()
4739 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4741 v.push_back (new_session_folder); /* full path */
4742 v.push_back (interchange_dir_name);
4743 v.push_back (new_session_name); /* just one directory/folder */
4744 v.push_back (typedir);
4745 v.push_back (Glib::path_get_basename (old_path));
4747 return Glib::build_filename (v);
4751 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4754 v.push_back (new_session_folder); /* full path */
4755 v.push_back (interchange_dir_name);
4756 v.push_back (new_session_name);
4757 v.push_back (ARDOUR::sound_dir_name);
4758 v.push_back (filename);
4760 return Glib::build_filename (v);
4764 Session::save_as (SaveAs& saveas)
4766 vector<string> files;
4767 string current_folder = Glib::path_get_dirname (_path);
4768 string new_folder = legalize_for_path (saveas.new_name);
4769 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4770 int64_t total_bytes = 0;
4774 int32_t internal_file_cnt = 0;
4776 vector<string> do_not_copy_extensions;
4777 do_not_copy_extensions.push_back (statefile_suffix);
4778 do_not_copy_extensions.push_back (pending_suffix);
4779 do_not_copy_extensions.push_back (backup_suffix);
4780 do_not_copy_extensions.push_back (temp_suffix);
4781 do_not_copy_extensions.push_back (history_suffix);
4783 /* get total size */
4785 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4787 /* need to clear this because
4788 * find_files_matching_filter() is cumulative
4793 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4795 all += files.size();
4797 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4799 g_stat ((*i).c_str(), &gsb);
4800 total_bytes += gsb.st_size;
4804 /* save old values so we can switch back if we are not switching to the new session */
4806 string old_path = _path;
4807 string old_name = _name;
4808 string old_snapshot = _current_snapshot_name;
4809 string old_sd = _session_dir->root_path();
4810 vector<string> old_search_path[DataType::num_types];
4811 string old_config_search_path[DataType::num_types];
4813 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4814 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4815 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4816 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4818 /* switch session directory */
4820 (*_session_dir) = to_dir;
4822 /* create new tree */
4824 if (!_session_dir->create()) {
4825 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4830 /* copy all relevant files. Find each location in session_dirs,
4831 * and copy files from there to target.
4834 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4836 /* need to clear this because
4837 * find_files_matching_filter() is cumulative
4842 const size_t prefix_len = (*sd).path.size();
4844 /* Work just on the files within this session dir */
4846 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4848 /* add dir separator to protect against collisions with
4849 * track names (e.g. track named "audiofiles" or
4853 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4854 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4855 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4857 /* copy all the files. Handling is different for media files
4858 than others because of the *silly* subtree we have below the interchange
4859 folder. That really was a bad idea, but I'm not fixing it as part of
4860 implementing ::save_as().
4863 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4865 std::string from = *i;
4868 string filename = Glib::path_get_basename (from);
4869 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4870 if (filename == ".DS_STORE") {
4875 if (from.find (audiofile_dir_string) != string::npos) {
4877 /* audio file: only copy if asked */
4879 if (saveas.include_media && saveas.copy_media) {
4881 string to = make_new_media_path (*i, to_dir, new_folder);
4883 info << "media file copying from " << from << " to " << to << endmsg;
4885 if (!copy_file (from, to)) {
4886 throw Glib::FileError (Glib::FileError::IO_ERROR,
4887 string_compose(_("\ncopying \"%1\" failed !"), from));
4891 /* we found media files inside the session folder */
4893 internal_file_cnt++;
4895 } else if (from.find (midifile_dir_string) != string::npos) {
4897 /* midi file: always copy unless
4898 * creating an empty new session
4901 if (saveas.include_media) {
4903 string to = make_new_media_path (*i, to_dir, new_folder);
4905 info << "media file copying from " << from << " to " << to << endmsg;
4907 if (!copy_file (from, to)) {
4908 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4912 /* we found media files inside the session folder */
4914 internal_file_cnt++;
4916 } else if (from.find (analysis_dir_string) != string::npos) {
4918 /* make sure analysis dir exists in
4919 * new session folder, but we're not
4920 * copying analysis files here, see
4924 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4929 /* normal non-media file. Don't copy state, history, etc.
4932 bool do_copy = true;
4934 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4935 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4936 /* end of filename matches extension, do not copy file */
4942 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4943 /* don't copy peakfiles if
4944 * we're not copying media
4950 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4952 info << "attempting to make directory/folder " << to << endmsg;
4954 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4955 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4958 info << "attempting to copy " << from << " to " << to << endmsg;
4960 if (!copy_file (from, to)) {
4961 throw Glib::FileError (Glib::FileError::IO_ERROR,
4962 string_compose(_("\ncopying \"%1\" failed !"), from));
4967 /* measure file size even if we're not going to copy so that our Progress
4968 signals are correct, since we included these do-not-copy files
4969 in the computation of the total size and file count.
4973 g_stat (from.c_str(), &gsb);
4974 copied += gsb.st_size;
4977 double fraction = (double) copied / total_bytes;
4979 bool keep_going = true;
4981 if (saveas.copy_media) {
4983 /* no need or expectation of this if
4984 * media is not being copied, because
4985 * it will be fast(ish).
4988 /* tell someone "X percent, file M of N"; M is one-based */
4990 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4998 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
5004 /* copy optional folders, if any */
5006 string old = plugins_dir ();
5007 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5008 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5009 copy_files (old, newdir);
5012 old = externals_dir ();
5013 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5014 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5015 copy_files (old, newdir);
5018 old = automation_dir ();
5019 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5020 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5021 copy_files (old, newdir);
5024 if (saveas.include_media) {
5026 if (saveas.copy_media) {
5027 #ifndef PLATFORM_WINDOWS
5028 /* There are problems with analysis files on
5029 * Windows, because they used a colon in their
5030 * names as late as 4.0. Colons are not legal
5031 * under Windows even if NTFS allows them.
5033 * This is a tricky problem to solve so for
5034 * just don't copy these files. They will be
5035 * regenerated as-needed anyway, subject to the
5036 * existing issue that the filenames will be
5037 * rejected by Windows, which is a separate
5038 * problem (though related).
5041 /* only needed if we are copying media, since the
5042 * analysis data refers to media data
5045 old = analysis_dir ();
5046 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5047 string newdir = Glib::build_filename (to_dir, "analysis");
5048 copy_files (old, newdir);
5050 #endif /* PLATFORM_WINDOWS */
5055 set_snapshot_name (saveas.new_name);
5056 _name = saveas.new_name;
5058 if (saveas.include_media && !saveas.copy_media) {
5060 /* reset search paths of the new session (which we're pretending to be right now) to
5061 include the original session search path, so we can still find all audio.
5064 if (internal_file_cnt) {
5065 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5066 ensure_search_path_includes (*s, DataType::AUDIO);
5067 cerr << "be sure to include " << *s << " for audio" << endl;
5070 /* we do not do this for MIDI because we copy
5071 all MIDI files if saveas.include_media is
5077 bool was_dirty = dirty ();
5079 save_default_options ();
5081 if (saveas.copy_media && saveas.copy_external) {
5082 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5083 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5087 saveas.final_session_folder_name = _path;
5089 store_recent_sessions (_name, _path);
5091 if (!saveas.switch_to) {
5093 /* save the new state */
5095 save_state ("", false, false, !saveas.include_media);
5097 /* switch back to the way things were */
5101 set_snapshot_name (old_snapshot);
5103 (*_session_dir) = old_sd;
5109 if (internal_file_cnt) {
5110 /* reset these to their original values */
5111 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5112 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5117 /* prune session dirs, and update disk space statistics
5122 session_dirs.clear ();
5123 session_dirs.push_back (sp);
5124 refresh_disk_space ();
5126 _writable = exists_and_writable (_path);
5128 /* ensure that all existing tracks reset their current capture source paths
5130 reset_write_sources (true, true);
5132 /* creating new write sources marks the session as
5133 dirty. If the new session is empty, then
5134 save_state() thinks we're saving a template and will
5135 not mark the session as clean. So do that here,
5136 before we save state.
5139 if (!saveas.include_media) {
5143 save_state ("", false, false, !saveas.include_media);
5145 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5146 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5149 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5150 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5156 if (fs->within_session()) {
5157 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5158 fs->set_path (newpath);
5163 } catch (Glib::FileError& e) {
5165 saveas.failure_message = e.what();
5167 /* recursively remove all the directories */
5169 remove_directory (to_dir);
5177 saveas.failure_message = _("unknown reason");
5179 /* recursively remove all the directories */
5181 remove_directory (to_dir);
5191 static void set_progress (Progress* p, size_t n, size_t t)
5193 p->set_progress (float (n) / float(t));
5197 Session::archive_session (const std::string& dest,
5198 const std::string& name,
5199 ArchiveEncode compress_audio,
5200 FileArchive::CompressionLevel compression_level,
5201 bool only_used_sources,
5204 if (dest.empty () || name.empty ()) {
5208 /* We are going to temporarily change some source properties,
5209 * don't allow any concurrent saves (periodic or otherwise */
5210 Glib::Threads::Mutex::Lock lm (save_source_lock);
5212 disable_record (false);
5214 /* save current values */
5215 string old_path = _path;
5216 string old_name = _name;
5217 string old_snapshot = _current_snapshot_name;
5218 string old_sd = _session_dir->root_path();
5219 string old_config_search_path[DataType::num_types];
5220 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5221 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5223 /* ensure that session-path is included in search-path */
5225 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5226 if ((*sd).path == old_path) {
5234 /* create temporary dir to save session to */
5235 #ifdef PLATFORM_WINDOWS
5236 char tmp[256] = "C:\\TEMP\\";
5237 GetTempPath (sizeof (tmp), tmp);
5239 char const* tmp = getenv("TMPDIR");
5244 if ((strlen (tmp) + 21) > 1024) {
5249 strcpy (tmptpl, tmp);
5250 strcat (tmptpl, "ardourarchive-XXXXXX");
5251 char* tmpdir = g_mkdtemp (tmptpl);
5257 std::string to_dir = std::string (tmpdir);
5259 /* switch session directory temporarily */
5260 (*_session_dir) = to_dir;
5262 if (!_session_dir->create()) {
5263 (*_session_dir) = old_sd;
5264 remove_directory (to_dir);
5268 /* prepare archive */
5269 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5271 PBD::ScopedConnectionList progress_connection;
5272 PBD::FileArchive ar (archive);
5274 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5277 /* collect files to archive */
5278 std::map<string,string> filemap;
5280 vector<string> do_not_copy_extensions;
5281 do_not_copy_extensions.push_back (statefile_suffix);
5282 do_not_copy_extensions.push_back (pending_suffix);
5283 do_not_copy_extensions.push_back (backup_suffix);
5284 do_not_copy_extensions.push_back (temp_suffix);
5285 do_not_copy_extensions.push_back (history_suffix);
5287 vector<string> blacklist_dirs;
5288 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5289 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5290 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5291 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5292 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5293 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5295 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5296 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5297 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5299 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5300 if (only_used_sources) {
5301 _playlists->sync_all_regions_with_regions ();
5302 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5305 /* collect audio sources for this session, calc total size for encoding
5306 * add option to only include *used* sources (see Session::cleanup_sources)
5308 size_t total_size = 0;
5310 Glib::Threads::Mutex::Lock lm (source_lock);
5312 /* build a list of used names */
5313 std::set<std::string> audio_file_names;
5314 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5315 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5318 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5319 if (!afs || afs->readable_length () == 0) {
5322 if (only_used_sources) {
5326 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5330 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5333 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5334 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5337 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5338 if (!afs || afs->readable_length () == 0) {
5342 if (only_used_sources) {
5346 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5351 std::string from = afs->path();
5353 if (compress_audio != NO_ENCODE) {
5354 total_size += afs->readable_length ();
5356 /* copy files as-is */
5357 if (!afs->within_session()) {
5358 string to = Glib::path_get_basename (from);
5360 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5361 * - avoid conflict with files existing in interchange
5362 * - avoid conflict with other embedded sources
5364 if (audio_file_names.find (to) == audio_file_names.end ()) {
5365 // we need a new name, add a '-<num>' before the '.<ext>'
5366 string bn = to.substr (0, to.find_last_of ('.'));
5367 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5368 to = bn + "-1" + ext;
5370 while (audio_file_names.find (to) == audio_file_names.end ()) {
5371 to = bump_name_once (to, '-');
5374 audio_file_names.insert (to);
5375 filemap[from] = make_new_audio_path (to, name, name);
5377 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5379 orig_origin[afs] = afs->origin ();
5380 afs->set_origin ("");
5383 filemap[from] = make_new_media_path (from, name, name);
5390 if (compress_audio != NO_ENCODE) {
5392 progress->set_progress (2); // set to "encoding"
5393 progress->set_progress (0);
5396 Glib::Threads::Mutex::Lock lm (source_lock);
5397 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5398 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5401 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5402 if (!afs || afs->readable_length () == 0) {
5406 if (only_used_sources) {
5410 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5415 orig_sources[afs] = afs->path();
5416 orig_gain[afs] = afs->gain();
5418 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5420 std::string channelsuffix = "";
5421 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5422 /* embedded external multi-channel files are converted to multiple-mono */
5423 channelsuffix = string_compose ("-c%1", afs->channel ());
5425 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5426 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5428 /* avoid name collisions of external files with same name */
5429 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5430 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5432 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5433 new_path = bump_name_once (new_path, '-');
5437 progress->descend ((float)afs->readable_length () / total_size);
5441 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5442 afs->replace_file (new_path);
5443 afs->set_gain (ns->gain(), true);
5446 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5450 progress->ascend ();
5456 progress->set_progress (-1); // set to "archiving"
5457 progress->set_progress (0);
5460 /* index files relevant for this session */
5461 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5462 vector<string> files;
5464 size_t prefix_len = (*sd).path.size();
5465 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5469 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5471 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5472 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5473 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5475 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5476 std::string from = *i;
5479 string filename = Glib::path_get_basename (from);
5480 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5481 if (filename == ".DS_STORE") {
5486 if (from.find (audiofile_dir_string) != string::npos) {
5488 } else if (from.find (midifile_dir_string) != string::npos) {
5489 filemap[from] = make_new_media_path (from, name, name);
5490 } else if (from.find (videofile_dir_string) != string::npos) {
5491 filemap[from] = make_new_media_path (from, name, name);
5493 bool do_copy = true;
5494 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5495 if (from.find (*v) != string::npos) {
5500 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5501 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5508 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5514 /* write session file */
5516 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5518 save_state (name, false, false, false, true, only_used_sources);
5520 save_default_options ();
5522 size_t prefix_len = _path.size();
5523 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5527 /* collect session-state files */
5528 vector<string> files;
5529 do_not_copy_extensions.clear ();
5530 do_not_copy_extensions.push_back (history_suffix);
5532 blacklist_dirs.clear ();
5533 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5535 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5536 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5537 std::string from = *i;
5538 bool do_copy = true;
5539 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5540 if (from.find (*v) != string::npos) {
5545 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5546 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5552 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5556 /* restore original values */
5559 set_snapshot_name (old_snapshot);
5560 (*_session_dir) = old_sd;
5561 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5562 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5564 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5565 i->first->set_origin (i->second);
5567 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5568 i->first->replace_file (i->second);
5570 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5571 i->first->set_gain (i->second, true);
5574 int rv = ar.create (filemap, compression_level);
5575 remove_directory (to_dir);
5581 Session::undo (uint32_t n)
5583 if (actively_recording()) {
5591 Session::redo (uint32_t n)
5593 if (actively_recording()) {