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.hpp"
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 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
369 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
370 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
372 } catch (AudioEngine::PortRegistrationFailure& err) {
373 error << err.what() << endmsg;
375 } catch (std::exception const & e) {
376 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
379 error << _("Unknown exception during session setup") << endmsg;
383 BootMessage (_("Reset Remote Controls"));
385 // send_full_time_code (0);
386 _engine.transport_locate (0);
388 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
389 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
393 BootMessage (_("Loading MIDNAM Patch files"));
395 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
396 /* initial program change will be delivered later; see ::config_changed() */
398 _state_of_the_state = Clean;
400 Port::set_connecting_blocked (false);
402 DirtyChanged (); /* EMIT SIGNAL */
404 /* Now, finally, we can fill the playback buffers */
406 BootMessage (_("Filling playback buffers"));
408 boost::shared_ptr<RouteList> rl = routes.reader();
409 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
410 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
411 if (trk && !trk->is_private_route()) {
412 trk->seek (_transport_sample, true);
420 Session::session_loaded ()
424 _state_of_the_state = Clean;
426 DirtyChanged (); /* EMIT SIGNAL */
430 } else if (state_was_pending) {
432 state_was_pending = false;
435 /* Now, finally, we can fill the playback buffers */
437 BootMessage (_("Filling playback buffers"));
438 force_locate (_transport_sample, false);
442 Session::raid_path () const
444 Searchpath raid_search_path;
446 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
447 raid_search_path += (*i).path;
450 return raid_search_path.to_string ();
454 Session::setup_raid_path (string path)
463 session_dirs.clear ();
465 Searchpath search_path(path);
466 Searchpath sound_search_path;
467 Searchpath midi_search_path;
469 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
471 sp.blocks = 0; // not needed
472 session_dirs.push_back (sp);
474 SessionDirectory sdir(sp.path);
476 sound_search_path += sdir.sound_path ();
477 midi_search_path += sdir.midi_path ();
480 // reset the round-robin soundfile path thingie
481 last_rr_session_dir = session_dirs.begin();
485 Session::path_is_within_session (const std::string& path)
487 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
488 if (PBD::path_is_within (i->path, path)) {
496 Session::ensure_subdirs ()
500 dir = session_directory().peak_path();
502 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
503 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
507 dir = session_directory().sound_path();
509 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
510 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
514 dir = session_directory().midi_path();
516 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
517 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
521 dir = session_directory().dead_path();
523 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
524 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
528 dir = session_directory().export_path();
530 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
531 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
535 if(Profile->get_mixbus()) {
536 dir = session_directory().backup_path();
538 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
539 error << string_compose(_("Session: cannot create session backup folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
544 dir = analysis_dir ();
546 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
547 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
551 dir = plugins_dir ();
553 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
554 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
558 dir = externals_dir ();
560 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
561 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
568 /** @param session_template directory containing session template, or empty.
569 * Caller must not hold process lock.
572 Session::create (const string& session_template, BusProfile const * bus_profile)
574 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
575 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
579 if (ensure_subdirs ()) {
583 _writable = exists_and_writable (_path);
585 if (!session_template.empty()) {
586 string in_path = session_template_dir_to_file (session_template);
588 FILE* in = g_fopen (in_path.c_str(), "rb");
591 /* no need to call legalize_for_path() since the string
592 * in session_template is already a legal path name
594 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
596 FILE* out = g_fopen (out_path.c_str(), "wb");
600 stringstream new_session;
603 size_t charsRead = fread (buf, sizeof(char), 1024, in);
606 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
611 if (charsRead == 0) {
614 new_session.write (buf, charsRead);
618 string file_contents = new_session.str();
619 size_t writeSize = file_contents.length();
620 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
621 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
629 /* Copy plugin state files from template to new session */
630 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
631 copy_recurse (template_plugins, plugins_dir ());
636 error << string_compose (_("Could not open %1 for writing session template"), out_path)
643 error << string_compose (_("Could not open session template %1 for reading"), in_path)
650 _state_of_the_state = Clean;
652 /* set up Master Out and Monitor Out if necessary */
656 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
657 if (bus_profile->master_out_channels) {
658 int rv = add_master_bus (count);
664 if (Config->get_use_monitor_bus())
665 add_monitor_section ();
673 Session::maybe_write_autosave()
675 if (dirty() && record_status() != Recording) {
676 save_state("", true);
681 Session::remove_pending_capture_state ()
683 std::string pending_state_file_path(_session_dir->root_path());
685 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
687 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) {
691 if (::g_unlink (pending_state_file_path.c_str()) != 0) {
692 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
693 pending_state_file_path, g_strerror (errno)) << endmsg;
697 cerr << "removed " << pending_state_file_path << endl;
702 /** Rename a state file.
703 * @param old_name Old snapshot name.
704 * @param new_name New snapshot name.
707 Session::rename_state (string old_name, string new_name)
709 if (old_name == _current_snapshot_name || old_name == _name) {
710 /* refuse to rename the current snapshot or the "main" one */
714 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
715 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
717 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
718 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
720 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
721 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
722 old_name, new_name, g_strerror(errno)) << endmsg;
726 /** Remove a state file.
727 * @param snapshot_name Snapshot name.
730 Session::remove_state (string snapshot_name)
732 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
733 // refuse to remove the current snapshot or the "main" one
737 std::string xml_path(_session_dir->root_path());
739 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
741 if (!create_backup_file (xml_path)) {
742 // don't remove it if a backup can't be made
743 // create_backup_file will log the error.
748 if (g_remove (xml_path.c_str()) != 0) {
749 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
750 xml_path, g_strerror (errno)) << endmsg;
753 StateSaved (snapshot_name); /* EMIT SIGNAL */
756 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
758 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only, bool for_archive, bool only_used_assets)
760 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
763 std::string xml_path(_session_dir->root_path());
765 /* prevent concurrent saves from different threads */
767 Glib::Threads::Mutex::Lock lm (save_state_lock);
768 Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK);
773 if (!_writable || cannot_save()) {
777 if (g_atomic_int_get(&_suspend_save)) {
781 _save_queued = false;
783 snapshot_t fork_state = NormalSave;
784 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) {
785 /* snapshot, close midi */
786 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
790 const int64_t save_start_time = g_get_monotonic_time();
793 /* tell sources we're saving first, in case they write out to a new file
794 * which should be saved with the state rather than the old one */
795 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
797 i->second->session_saved();
798 } catch (Evoral::SMF::FileError& e) {
799 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
803 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, for_archive);
805 SessionSaveUnderway (); /* EMIT SIGNAL */
807 bool mark_as_clean = true;
808 if (!snapshot_name.empty() && !switch_to_snapshot) {
809 mark_as_clean = false;
813 mark_as_clean = false;
814 tree.set_root (&get_template());
816 tree.set_root (&state (false, fork_state, only_used_assets));
819 if (snapshot_name.empty()) {
820 snapshot_name = _current_snapshot_name;
821 } else if (switch_to_snapshot) {
822 set_snapshot_name (snapshot_name);
825 assert (!snapshot_name.empty());
829 /* proper save: use statefile_suffix (.ardour in English) */
831 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
833 /* make a backup copy of the old file */
835 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
836 // create_backup_file will log the error
841 assert (snapshot_name == _current_snapshot_name);
842 /* pending save: use pending_suffix (.pending in English) */
843 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
846 std::string tmp_path(_session_dir->root_path());
847 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
850 cerr << "actually writing state to " << tmp_path << endl;
853 if (!tree.write (tmp_path)) {
854 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
855 if (g_remove (tmp_path.c_str()) != 0) {
856 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
857 tmp_path, g_strerror (errno)) << endmsg;
864 cerr << "renaming state to " << xml_path << endl;
867 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
868 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
869 tmp_path, xml_path, g_strerror(errno)) << endmsg;
870 if (g_remove (tmp_path.c_str()) != 0) {
871 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
872 tmp_path, g_strerror (errno)) << endmsg;
878 //Mixbus auto-backup mechanism
879 if(Profile->get_mixbus()) {
880 if (pending) { //"pending" save means it's a backup, or some other non-user-initiated save; a good time to make a backup
881 // make a serialized safety backup
882 // (will make one periodically but only one per hour is left on disk)
883 // these backup files go into a separated folder
886 struct tm local_time;
888 localtime_r (&n, &local_time);
889 strftime (timebuf, sizeof(timebuf), "%y-%m-%d.%H", &local_time);
890 std::string save_path(session_directory().backup_path());
891 save_path += G_DIR_SEPARATOR;
892 save_path += legalize_for_path(_current_snapshot_name);
894 save_path += timebuf;
895 save_path += statefile_suffix;
896 if ( !tree.write (save_path) )
897 error << string_compose(_("Could not save backup file at path \"%1\" (%2)"),
898 save_path, g_strerror (errno)) << endmsg;
901 StateSaved (snapshot_name); /* EMIT SIGNAL */
904 if (!pending && !for_archive) {
906 save_history (snapshot_name);
909 unset_dirty (/* EMIT SIGNAL */ true);
912 StateSaved (snapshot_name); /* EMIT SIGNAL */
916 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
917 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
920 if (!pending && !for_archive && ! template_only) {
921 remove_pending_capture_state ();
928 Session::restore_state (string snapshot_name)
931 if (load_state (snapshot_name) == 0) {
932 set_state (*state_tree->root(), Stateful::loading_state_version);
936 // unknown_enumeration
944 Session::load_state (string snapshot_name)
949 state_was_pending = false;
951 /* check for leftover pending state from a crashed capture attempt */
953 std::string xmlpath(_session_dir->root_path());
954 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
956 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
958 /* there is pending state from a crashed capture attempt */
960 boost::optional<int> r = AskAboutPendingState();
961 if (r.get_value_or (1)) {
962 state_was_pending = true;
966 if (!state_was_pending) {
967 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
970 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
971 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
972 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
973 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
978 state_tree = new XMLTree;
982 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
984 if (!state_tree->read (xmlpath)) {
985 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
991 XMLNode const & root (*state_tree->root());
993 if (root.name() != X_("Session")) {
994 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
1000 std::string version;
1001 root.get_property ("version", version);
1002 Stateful::loading_state_version = parse_stateful_loading_version (version);
1004 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
1005 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
1006 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
1009 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1011 std::string backup_path(_session_dir->root_path());
1012 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1013 backup_path = Glib::build_filename (backup_path, backup_filename);
1015 // only create a backup for a given statefile version once
1017 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1019 VersionMismatch (xmlpath, backup_path);
1021 if (!copy_file (xmlpath, backup_path)) {;
1027 save_snapshot_name (snapshot_name);
1033 Session::load_options (const XMLNode& node)
1035 config.set_variables (node);
1040 Session::save_default_options ()
1042 return config.save_state();
1046 Session::get_state ()
1048 /* this is not directly called, but required by PBD::Stateful */
1050 return state (false, NormalSave);
1054 Session::get_template ()
1056 /* if we don't disable rec-enable, diskstreams
1057 will believe they need to store their capture
1058 sources in their state node.
1061 disable_record (false);
1063 return state (true, NormalSave);
1066 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1067 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1070 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1072 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1075 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1079 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1082 XMLNode* node = new XMLNode("TrackState"); // XXX
1085 PlaylistSet playlists; // SessionPlaylists
1088 // these will work with new_route_from_template()
1089 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1090 child = node->add_child ("Routes");
1091 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1092 if ((*i)->is_auditioner()) {
1095 if ((*i)->is_master() || (*i)->is_monitor()) {
1098 child->add_child_nocopy ((*i)->get_state());
1099 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1101 playlists.insert (track->playlist ());
1105 // on load, Regions in the playlists need to resolve and map Source-IDs
1106 // also playlist needs to be merged or created with new-name..
1107 // ... and Diskstream in tracks adjusted to use the correct playlist
1108 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1109 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1110 child->add_child_nocopy ((*i)->get_state ());
1111 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1112 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1113 const Region::SourceList& sl = (*s)->sources ();
1114 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1115 sources.insert (*sli);
1120 child = node->add_child ("Sources");
1121 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1122 child->add_child_nocopy ((*i)->get_state ());
1123 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1125 #ifdef PLATFORM_WINDOWS
1128 string p = fs->path ();
1129 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1133 std::string sn = Glib::build_filename (path, "share.axml");
1136 tree.set_root (node);
1137 return tree.write (sn.c_str());
1141 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
1143 pl->deep_sources (*all_sources);
1148 struct route_id_compare {
1150 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1152 return r1->id () < r2->id ();
1158 Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets)
1161 XMLNode* node = new XMLNode("Session");
1164 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1166 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1168 child = node->add_child ("ProgramVersion");
1169 child->set_property("created-with", created_with);
1171 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1172 child->set_property("modified-with", modified_with);
1174 /* store configuration settings */
1176 if (!save_template) {
1178 node->set_property ("name", _name);
1179 node->set_property ("sample-rate", _base_sample_rate);
1181 if (session_dirs.size() > 1) {
1185 vector<space_and_path>::iterator i = session_dirs.begin();
1186 vector<space_and_path>::iterator next;
1188 ++i; /* skip the first one */
1192 while (i != session_dirs.end()) {
1196 if (next != session_dirs.end()) {
1197 p += G_SEARCHPATH_SEPARATOR;
1206 child = node->add_child ("Path");
1207 child->add_content (p);
1209 node->set_property ("end-is-free", _session_range_is_free); //deprecated, but keep storing this value for compatibility with prior v5.
1210 node->set_property ("session-range-is-free", _session_range_is_free);
1213 /* save the ID counter */
1215 node->set_property ("id-counter", ID::counter());
1217 node->set_property ("name-counter", name_id_counter ());
1219 /* save the event ID counter */
1221 node->set_property ("event-counter", Evoral::event_id_counter());
1223 /* save the VCA counter */
1225 node->set_property ("vca-counter", VCA::get_next_vca_number());
1227 /* various options */
1229 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1230 if (!midi_port_nodes.empty()) {
1231 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1232 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1233 midi_port_stuff->add_child_nocopy (**n);
1235 node->add_child_nocopy (*midi_port_stuff);
1238 XMLNode& cfgxml (config.get_variables ());
1239 if (save_template) {
1240 /* exclude search-paths from template */
1241 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1242 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1243 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1245 node->add_child_nocopy (cfgxml);
1247 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1249 child = node->add_child ("Sources");
1251 if (!save_template) {
1252 Glib::Threads::Mutex::Lock sl (source_lock);
1254 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1256 if (only_used_assets) {
1257 _playlists->sync_all_regions_with_regions ();
1258 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1261 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1263 /* Don't save information about non-file Sources, or
1264 * about non-destructive file sources that are empty
1265 * and unused by any regions.
1267 boost::shared_ptr<FileSource> fs;
1269 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1273 if (!fs->destructive()) {
1274 if (fs->empty() && !fs->used()) {
1279 if (only_used_assets) {
1280 /* skip only unused audio files */
1281 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1282 if (afs && !afs->used()) {
1285 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1290 if (snapshot_type != NormalSave && fs->within_session ()) {
1291 /* copy MIDI sources to new file
1293 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1294 * because the GUI (midi_region) has a direct pointer to the midi-model
1295 * of the source, as does UndoTransaction.
1297 * On the upside, .mid files are not kept open. The file is only open
1298 * when reading the model initially and when flushing the model to disk:
1299 * source->session_saved () or export.
1301 * We can change the _path of the existing source under the hood, keeping
1302 * all IDs, references and pointers intact.
1304 boost::shared_ptr<SMFSource> ms;
1305 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1306 const std::string ancestor_name = ms->ancestor_name();
1307 const std::string base = PBD::basename_nosuffix(ancestor_name);
1308 const string path = new_midi_source_path (base, false);
1310 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1311 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1312 Source::Lock lm (ms->mutex());
1314 // TODO special-case empty, removable() files: just create a new removable.
1315 // (load + write flushes the model and creates the file)
1317 ms->load_model (lm);
1319 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1320 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1322 if (snapshot_type == SnapshotKeep) {
1323 /* keep working on current session.
1325 * Save snapshot-state with the original filename.
1326 * Switch to use new path for future saves of the main session.
1328 child->add_child_nocopy (ms->get_state());
1332 * ~SMFSource unlinks removable() files.
1334 std::string npath (ms->path ());
1335 ms->replace_file (newsrc->path ());
1336 newsrc->replace_file (npath);
1338 if (snapshot_type == SwitchToSnapshot) {
1339 /* save and switch to snapshot.
1341 * Leave the old file in place (as is).
1342 * Snapshot uses new source directly
1344 child->add_child_nocopy (ms->get_state());
1351 child->add_child_nocopy (siter->second->get_state());
1355 child = node->add_child ("Regions");
1357 if (!save_template) {
1358 Glib::Threads::Mutex::Lock rl (region_lock);
1360 if (!only_used_assets) {
1361 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1362 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1363 boost::shared_ptr<Region> r = i->second;
1364 /* only store regions not attached to playlists */
1365 if (r->playlist() == 0) {
1366 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1367 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1369 child->add_child_nocopy (r->get_state ());
1375 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1377 if (!cassocs.empty()) {
1378 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1380 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1381 if (i->first->playlist () == 0 && only_used_assets) {
1384 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1385 can->set_property (X_("copy"), i->first->id());
1386 can->set_property (X_("original"), i->second->id());
1387 ca->add_child_nocopy (*can);
1388 /* see above, child is still "Regions" here */
1389 if (i->second->playlist() == 0 && only_used_assets) {
1390 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1391 child->add_child_nocopy (ar->get_basic_state ());
1393 child->add_child_nocopy (ar->get_state ());
1400 if (!save_template) {
1402 node->add_child_nocopy (_selection->get_state());
1405 node->add_child_nocopy (_locations->get_state());
1408 Locations loc (*this);
1409 const bool was_dirty = dirty();
1410 // for a template, just create a new Locations, populate it
1411 // with the default start and end, and get the state for that.
1412 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1413 range->set (max_samplepos, 0);
1415 XMLNode& locations_state = loc.get_state();
1417 node->add_child_nocopy (locations_state);
1419 /* adding a location above will have marked the session
1420 * dirty. This is an artifact, so fix it if the session wasn't
1429 child = node->add_child ("Bundles");
1431 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1432 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1433 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1435 child->add_child_nocopy (b->get_state());
1440 node->add_child_nocopy (_vca_manager->get_state());
1442 child = node->add_child ("Routes");
1444 boost::shared_ptr<RouteList> r = routes.reader ();
1446 route_id_compare cmp;
1447 RouteList xml_node_order (*r);
1448 xml_node_order.sort (cmp);
1450 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1451 if (!(*i)->is_auditioner()) {
1452 if (save_template) {
1453 child->add_child_nocopy ((*i)->get_template());
1455 child->add_child_nocopy ((*i)->get_state());
1461 _playlists->add_state (node, save_template, !only_used_assets);
1463 child = node->add_child ("RouteGroups");
1464 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1465 child->add_child_nocopy ((*i)->get_state());
1469 XMLNode* gain_child = node->add_child ("Click");
1470 gain_child->add_child_nocopy (_click_io->get_state ());
1471 gain_child->add_child_nocopy (_click_gain->get_state ());
1475 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1476 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1479 node->add_child_nocopy (_speakers->get_state());
1480 node->add_child_nocopy (_tempo_map->get_state());
1481 node->add_child_nocopy (get_control_protocol_state());
1484 node->add_child_copy (*_extra_xml);
1488 Glib::Threads::Mutex::Lock lm (lua_lock);
1491 luabridge::LuaRef savedstate ((*_lua_save)());
1492 saved = savedstate.cast<std::string>();
1494 lua.collect_garbage ();
1497 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1498 std::string b64s (b64);
1501 XMLNode* script_node = new XMLNode (X_("Script"));
1502 script_node->set_property (X_("lua"), LUA_VERSION);
1503 script_node->add_content (b64s);
1504 node->add_child_nocopy (*script_node);
1511 Session::get_control_protocol_state ()
1513 return ControlProtocolManager::instance().get_state ();
1517 Session::set_state (const XMLNode& node, int version)
1524 _state_of_the_state = StateOfTheState (_state_of_the_state | CannotSave);
1526 if (node.name() != X_("Session")) {
1527 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1531 node.get_property ("name", _name);
1533 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1535 _nominal_sample_rate = _base_sample_rate;
1537 assert (AudioEngine::instance()->running ());
1538 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1539 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1540 if (r.get_value_or (0)) {
1546 created_with = "unknown";
1547 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1548 child->get_property (X_("created-with"), created_with);
1551 setup_raid_path(_session_dir->root_path());
1553 node.get_property (X_("end-is-free"), _session_range_is_free); //deprectated, but use old values if they are in the config
1555 node.get_property (X_("session-range-is-free"), _session_range_is_free);
1558 if (node.get_property (X_("id-counter"), counter)) {
1559 ID::init_counter (counter);
1561 /* old sessions used a timebased counter, so fake
1562 * the startup ID counter based on a standard
1567 ID::init_counter (now);
1570 if (node.get_property (X_("name-counter"), counter)) {
1571 init_name_id_counter (counter);
1574 if (node.get_property (X_("event-counter"), counter)) {
1575 Evoral::init_event_id_counter (counter);
1578 if (node.get_property (X_("vca-counter"), counter)) {
1579 VCA::set_next_vca_number (counter);
1581 VCA::set_next_vca_number (1);
1584 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1585 _midi_ports->set_midi_port_states (child->children());
1588 IO::disable_connecting ();
1590 Stateful::save_extra_xml (node);
1592 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1593 load_options (*child);
1594 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1595 load_options (*child);
1597 error << _("Session: XML state has no options section") << endmsg;
1600 if (version >= 3000) {
1601 if ((child = find_named_node (node, "Metadata")) == 0) {
1602 warning << _("Session: XML state has no metadata section") << endmsg;
1603 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1608 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1609 _speakers->set_state (*child, version);
1612 if ((child = find_named_node (node, "Sources")) == 0) {
1613 error << _("Session: XML state has no sources section") << endmsg;
1615 } else if (load_sources (*child)) {
1619 if ((child = find_named_node (node, "TempoMap")) == 0) {
1620 error << _("Session: XML state has no Tempo Map section") << endmsg;
1622 } else if (_tempo_map->set_state (*child, version)) {
1626 if ((child = find_named_node (node, "Locations")) == 0) {
1627 error << _("Session: XML state has no locations section") << endmsg;
1629 } else if (_locations->set_state (*child, version)) {
1633 locations_changed ();
1635 if (_session_range_location) {
1636 AudioFileSource::set_header_position_offset (_session_range_location->start());
1639 if ((child = find_named_node (node, "Regions")) == 0) {
1640 error << _("Session: XML state has no Regions section") << endmsg;
1642 } else if (load_regions (*child)) {
1646 if ((child = find_named_node (node, "Playlists")) == 0) {
1647 error << _("Session: XML state has no playlists section") << endmsg;
1649 } else if (_playlists->load (*this, *child)) {
1653 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1655 } else if (_playlists->load_unused (*this, *child)) {
1659 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1660 if (load_compounds (*child)) {
1665 if (version >= 3000) {
1666 if ((child = find_named_node (node, "Bundles")) == 0) {
1667 warning << _("Session: XML state has no bundles section") << endmsg;
1670 /* We can't load Bundles yet as they need to be able
1671 * to convert from port names to Port objects, which can't happen until
1673 _bundle_xml_node = new XMLNode (*child);
1677 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1678 _vca_manager->set_state (*child, version);
1681 if ((child = find_named_node (node, "Routes")) == 0) {
1682 error << _("Session: XML state has no routes section") << endmsg;
1684 } else if (load_routes (*child, version)) {
1688 /* Now that we Tracks have been loaded and playlists are assigned */
1689 _playlists->update_tracking ();
1691 /* Now that we have Routes and masters loaded, connect them if appropriate */
1693 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1695 if (version >= 3000) {
1697 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1698 error << _("Session: XML state has no route groups section") << endmsg;
1700 } else if (load_route_groups (*child, version)) {
1704 } else if (version < 3000) {
1706 if ((child = find_named_node (node, "EditGroups")) == 0) {
1707 error << _("Session: XML state has no edit groups section") << endmsg;
1709 } else if (load_route_groups (*child, version)) {
1713 if ((child = find_named_node (node, "MixGroups")) == 0) {
1714 error << _("Session: XML state has no mix groups section") << endmsg;
1716 } else if (load_route_groups (*child, version)) {
1721 if ((child = find_named_node (node, "Click")) == 0) {
1722 warning << _("Session: XML state has no click section") << endmsg;
1723 } else if (_click_io) {
1724 setup_click_state (&node);
1727 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1728 ControlProtocolManager::instance().set_state (*child, 1 /* here: session-specific state */);
1731 if ((child = find_named_node (node, "Script"))) {
1732 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1733 if (!(*n)->is_content ()) { continue; }
1735 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1737 Glib::Threads::Mutex::Lock lm (lua_lock);
1738 (*_lua_load)(std::string ((const char*)buf, size));
1739 } catch (luabridge::LuaException const& e) {
1740 cerr << "LuaException:" << e.what () << endl;
1746 if ((child = find_named_node (node, X_("Selection")))) {
1747 _selection->set_state (*child, version);
1750 update_route_record_state ();
1752 /* here beginneth the second phase ... */
1753 set_snapshot_name (_current_snapshot_name);
1755 StateReady (); /* EMIT SIGNAL */
1768 Session::load_routes (const XMLNode& node, int version)
1771 XMLNodeConstIterator niter;
1772 RouteList new_routes;
1774 nlist = node.children();
1778 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1780 boost::shared_ptr<Route> route;
1782 if (version < 3000) {
1783 route = XMLRouteFactory_2X (**niter, version);
1784 } else if (version < 5000) {
1785 route = XMLRouteFactory_3X (**niter, version);
1787 route = XMLRouteFactory (**niter, version);
1791 error << _("Session: cannot create Route from XML description.") << endmsg;
1795 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1797 new_routes.push_back (route);
1800 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1802 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1804 BootMessage (_("Finished adding tracks/busses"));
1809 boost::shared_ptr<Route>
1810 Session::XMLRouteFactory (const XMLNode& node, int version)
1812 boost::shared_ptr<Route> ret;
1814 if (node.name() != "Route") {
1818 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1821 pl_prop = node.property (X_("midi-playlist"));
1824 DataType type = DataType::AUDIO;
1825 node.get_property("default-type", type);
1827 assert (type != DataType::NIL);
1831 /* has at least 1 playlist, therefore a track ... */
1833 boost::shared_ptr<Track> track;
1835 if (type == DataType::AUDIO) {
1836 track.reset (new AudioTrack (*this, string())); // name will be reset from XML in ::set_state() below
1838 track.reset (new MidiTrack (*this, string())); // name will be reset from XML in ::set_state() below
1841 if (track->init()) {
1845 if (track->set_state (node, version)) {
1849 BOOST_MARK_TRACK (track);
1853 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1854 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1857 if (r->init () == 0 && r->set_state (node, version) == 0) {
1858 BOOST_MARK_ROUTE (r);
1866 boost::shared_ptr<Route>
1867 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1869 boost::shared_ptr<Route> ret;
1871 if (node.name() != "Route") {
1875 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1877 DataType type = DataType::AUDIO;
1878 node.get_property("default-type", type);
1880 assert (type != DataType::NIL);
1884 boost::shared_ptr<Track> track;
1886 if (type == DataType::AUDIO) {
1887 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1889 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1892 if (track->init()) {
1896 if (track->set_state (node, version)) {
1900 BOOST_MARK_TRACK (track);
1904 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1905 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1907 if (r->init () == 0 && r->set_state (node, version) == 0) {
1908 BOOST_MARK_ROUTE (r);
1916 boost::shared_ptr<Route>
1917 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1919 boost::shared_ptr<Route> ret;
1921 if (node.name() != "Route") {
1925 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1927 ds_prop = node.property (X_("diskstream"));
1930 DataType type = DataType::AUDIO;
1931 node.get_property("default-type", type);
1933 assert (type != DataType::NIL);
1937 /* see comment in current ::set_state() regarding diskstream
1938 * state and DiskReader/DiskWRiter.
1941 error << _("Could not find diskstream for route") << endmsg;
1942 return boost::shared_ptr<Route> ();
1944 boost::shared_ptr<Track> track;
1946 if (type == DataType::AUDIO) {
1947 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1949 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1952 if (track->init()) {
1956 if (track->set_state (node, version)) {
1960 BOOST_MARK_TRACK (track);
1964 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1965 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1967 if (r->init () == 0 && r->set_state (node, version) == 0) {
1968 BOOST_MARK_ROUTE (r);
1977 Session::load_regions (const XMLNode& node)
1980 XMLNodeConstIterator niter;
1981 boost::shared_ptr<Region> region;
1983 nlist = node.children();
1987 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1988 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1989 error << _("Session: cannot create Region from XML description.");
1990 XMLProperty const * name = (**niter).property("name");
1993 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
2004 Session::load_compounds (const XMLNode& node)
2006 XMLNodeList calist = node.children();
2007 XMLNodeConstIterator caiter;
2008 XMLProperty const * caprop;
2010 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
2011 XMLNode* ca = *caiter;
2015 if ((caprop = ca->property (X_("original"))) == 0) {
2018 orig_id = caprop->value();
2020 if ((caprop = ca->property (X_("copy"))) == 0) {
2023 copy_id = caprop->value();
2025 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2026 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2028 if (!orig || !copy) {
2029 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2035 RegionFactory::add_compound_association (orig, copy);
2042 Session::load_nested_sources (const XMLNode& node)
2045 XMLNodeConstIterator niter;
2047 nlist = node.children();
2049 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2050 if ((*niter)->name() == "Source") {
2052 /* it may already exist, so don't recreate it unnecessarily
2055 XMLProperty const * prop = (*niter)->property (X_("id"));
2057 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2061 ID source_id (prop->value());
2063 if (!source_by_id (source_id)) {
2066 SourceFactory::create (*this, **niter, true);
2068 catch (failed_constructor& err) {
2069 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2076 boost::shared_ptr<Region>
2077 Session::XMLRegionFactory (const XMLNode& node, bool full)
2079 XMLProperty const * type = node.property("type");
2083 const XMLNodeList& nlist = node.children();
2085 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2086 XMLNode *child = (*niter);
2087 if (child->name() == "NestedSource") {
2088 load_nested_sources (*child);
2092 if (!type || type->value() == "audio") {
2093 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2094 } else if (type->value() == "midi") {
2095 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2098 } catch (failed_constructor& err) {
2099 return boost::shared_ptr<Region> ();
2102 return boost::shared_ptr<Region> ();
2105 boost::shared_ptr<AudioRegion>
2106 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2108 XMLProperty const * prop;
2109 boost::shared_ptr<Source> source;
2110 boost::shared_ptr<AudioSource> as;
2112 SourceList master_sources;
2113 uint32_t nchans = 1;
2116 if (node.name() != X_("Region")) {
2117 return boost::shared_ptr<AudioRegion>();
2120 node.get_property (X_("channels"), nchans);
2122 if ((prop = node.property ("name")) == 0) {
2123 cerr << "no name for this region\n";
2127 if ((prop = node.property (X_("source-0"))) == 0) {
2128 if ((prop = node.property ("source")) == 0) {
2129 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2130 return boost::shared_ptr<AudioRegion>();
2134 PBD::ID s_id (prop->value());
2136 if ((source = source_by_id (s_id)) == 0) {
2137 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2138 return boost::shared_ptr<AudioRegion>();
2141 as = boost::dynamic_pointer_cast<AudioSource>(source);
2143 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2144 return boost::shared_ptr<AudioRegion>();
2147 sources.push_back (as);
2149 /* pickup other channels */
2151 for (uint32_t n=1; n < nchans; ++n) {
2152 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2153 if ((prop = node.property (buf)) != 0) {
2155 PBD::ID id2 (prop->value());
2157 if ((source = source_by_id (id2)) == 0) {
2158 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2159 return boost::shared_ptr<AudioRegion>();
2162 as = boost::dynamic_pointer_cast<AudioSource>(source);
2164 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2165 return boost::shared_ptr<AudioRegion>();
2167 sources.push_back (as);
2171 for (uint32_t n = 0; n < nchans; ++n) {
2172 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2173 if ((prop = node.property (buf)) != 0) {
2175 PBD::ID id2 (prop->value());
2177 if ((source = source_by_id (id2)) == 0) {
2178 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2179 return boost::shared_ptr<AudioRegion>();
2182 as = boost::dynamic_pointer_cast<AudioSource>(source);
2184 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2185 return boost::shared_ptr<AudioRegion>();
2187 master_sources.push_back (as);
2192 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2194 /* a final detail: this is the one and only place that we know how long missing files are */
2196 if (region->whole_file()) {
2197 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2198 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2200 sfp->set_length (region->length());
2205 if (!master_sources.empty()) {
2206 if (master_sources.size() != nchans) {
2207 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2209 region->set_master_sources (master_sources);
2217 catch (failed_constructor& err) {
2218 return boost::shared_ptr<AudioRegion>();
2222 boost::shared_ptr<MidiRegion>
2223 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2225 XMLProperty const * prop;
2226 boost::shared_ptr<Source> source;
2227 boost::shared_ptr<MidiSource> ms;
2230 if (node.name() != X_("Region")) {
2231 return boost::shared_ptr<MidiRegion>();
2234 if ((prop = node.property ("name")) == 0) {
2235 cerr << "no name for this region\n";
2239 if ((prop = node.property (X_("source-0"))) == 0) {
2240 if ((prop = node.property ("source")) == 0) {
2241 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2242 return boost::shared_ptr<MidiRegion>();
2246 PBD::ID s_id (prop->value());
2248 if ((source = source_by_id (s_id)) == 0) {
2249 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2250 return boost::shared_ptr<MidiRegion>();
2253 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2255 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2256 return boost::shared_ptr<MidiRegion>();
2259 sources.push_back (ms);
2262 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2263 /* a final detail: this is the one and only place that we know how long missing files are */
2265 if (region->whole_file()) {
2266 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2267 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2269 sfp->set_length (region->length());
2277 catch (failed_constructor& err) {
2278 return boost::shared_ptr<MidiRegion>();
2283 Session::get_sources_as_xml ()
2286 XMLNode* node = new XMLNode (X_("Sources"));
2287 Glib::Threads::Mutex::Lock lm (source_lock);
2289 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2290 node->add_child_nocopy (i->second->get_state());
2297 Session::reset_write_sources (bool mark_write_complete, bool force)
2299 boost::shared_ptr<RouteList> rl = routes.reader();
2300 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2301 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2303 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
2304 tr->reset_write_sources(mark_write_complete, force);
2305 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2311 Session::load_sources (const XMLNode& node)
2314 XMLNodeConstIterator niter;
2315 /* don't need this but it stops some
2316 * versions of gcc complaining about
2317 * discarded return values.
2319 boost::shared_ptr<Source> source;
2321 nlist = node.children();
2324 std::map<std::string, std::string> relocation;
2326 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2327 #ifdef PLATFORM_WINDOWS
2331 XMLNode srcnode (**niter);
2332 bool try_replace_abspath = true;
2336 #ifdef PLATFORM_WINDOWS
2337 // do not show "insert media" popups (files embedded from removable media).
2338 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2340 if ((source = XMLSourceFactory (srcnode)) == 0) {
2341 error << _("Session: cannot create Source from XML description.") << endmsg;
2343 #ifdef PLATFORM_WINDOWS
2344 SetErrorMode(old_mode);
2347 } catch (MissingSource& err) {
2348 #ifdef PLATFORM_WINDOWS
2349 SetErrorMode(old_mode);
2352 /* try previous abs path replacements first */
2353 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2354 std::string dir = Glib::path_get_dirname (err.path);
2355 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2356 if (rl != relocation.end ()) {
2357 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2358 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2359 srcnode.set_property ("origin", newpath);
2360 try_replace_abspath = false;
2367 _missing_file_replacement = "";
2369 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2370 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2371 PROGRAM_NAME) << endmsg;
2375 if (!no_questions_about_missing_files) {
2376 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2381 switch (user_choice) {
2383 /* user added a new search location
2384 * or selected a new absolute path,
2386 if (Glib::path_is_absolute (err.path)) {
2387 if (!_missing_file_replacement.empty ()) {
2388 /* replace origin, in XML */
2389 std::string newpath = Glib::build_filename (
2390 _missing_file_replacement, Glib::path_get_basename (err.path));
2391 srcnode.set_property ("origin", newpath);
2392 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2393 _missing_file_replacement = "";
2400 /* user asked to quit the entire session load */
2404 no_questions_about_missing_files = true;
2408 no_questions_about_missing_files = true;
2415 case DataType::AUDIO:
2416 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2419 case DataType::MIDI:
2420 /* The MIDI file is actually missing so
2421 * just create a new one in the same
2422 * location. Do not announce its
2426 if (!Glib::path_is_absolute (err.path)) {
2427 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2429 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2434 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2435 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2436 /* reset ID to match the missing one */
2437 source->set_id (**niter);
2438 /* Now we can announce it */
2439 SourceFactory::SourceCreated (source);
2450 boost::shared_ptr<Source>
2451 Session::XMLSourceFactory (const XMLNode& node)
2453 if (node.name() != "Source") {
2454 return boost::shared_ptr<Source>();
2458 /* note: do peak building in another thread when loading session state */
2459 return SourceFactory::create (*this, node, true);
2462 catch (failed_constructor& err) {
2463 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2464 return boost::shared_ptr<Source>();
2469 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2471 if (cannot_save () || template_name.empty ()) {
2475 bool absolute_path = Glib::path_is_absolute (template_name);
2477 /* directory to put the template in */
2478 std::string template_dir_path;
2480 if (!absolute_path) {
2481 std::string user_template_dir(user_template_directory());
2483 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2484 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2485 user_template_dir, g_strerror (errno)) << endmsg;
2489 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2491 template_dir_path = template_name;
2494 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2495 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2496 template_dir_path) << endmsg;
2500 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2501 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2502 template_dir_path, g_strerror (errno)) << endmsg;
2507 std::string template_file_path;
2509 if (absolute_path) {
2510 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2512 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2515 SessionSaveUnderway (); /* EMIT SIGNAL */
2520 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2521 root = &get_template ();
2524 root->remove_nodes_and_delete (X_("description"));
2526 if (!description.empty()) {
2527 XMLNode* desc = new XMLNode (X_("description"));
2528 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2529 desc->add_child_nocopy (*desc_cont);
2531 root->add_child_nocopy (*desc);
2534 tree.set_root (root);
2536 if (!tree.write (template_file_path)) {
2537 error << _("template not saved") << endmsg;
2541 store_recent_templates (template_file_path);
2547 Session::refresh_disk_space ()
2549 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2551 Glib::Threads::Mutex::Lock lm (space_lock);
2553 /* get freespace on every FS that is part of the session path */
2555 _total_free_4k_blocks = 0;
2556 _total_free_4k_blocks_uncertain = false;
2558 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2559 #if defined(__NetBSD__)
2560 struct statvfs statfsbuf;
2562 statvfs (i->path.c_str(), &statfsbuf);
2564 struct statfs statfsbuf;
2566 statfs (i->path.c_str(), &statfsbuf);
2568 double const scale = statfsbuf.f_bsize / 4096.0;
2570 /* See if this filesystem is read-only */
2571 struct statvfs statvfsbuf;
2572 statvfs (i->path.c_str(), &statvfsbuf);
2574 /* f_bavail can be 0 if it is undefined for whatever
2575 filesystem we are looking at; Samba shares mounted
2576 via GVFS are an example of this.
2578 if (statfsbuf.f_bavail == 0) {
2579 /* block count unknown */
2581 i->blocks_unknown = true;
2582 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2583 /* read-only filesystem */
2585 i->blocks_unknown = false;
2587 /* read/write filesystem with known space */
2588 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2589 i->blocks_unknown = false;
2592 _total_free_4k_blocks += i->blocks;
2593 if (i->blocks_unknown) {
2594 _total_free_4k_blocks_uncertain = true;
2597 #elif defined PLATFORM_WINDOWS
2598 vector<string> scanned_volumes;
2599 vector<string>::iterator j;
2600 vector<space_and_path>::iterator i;
2601 DWORD nSectorsPerCluster, nBytesPerSector,
2602 nFreeClusters, nTotalClusters;
2606 _total_free_4k_blocks = 0;
2608 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2609 strncpy (disk_drive, (*i).path.c_str(), 3);
2613 volume_found = false;
2614 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2616 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2617 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2618 i->blocks = (uint32_t)(nFreeBytes / 4096);
2620 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2621 if (0 == j->compare(disk_drive)) {
2622 volume_found = true;
2627 if (!volume_found) {
2628 scanned_volumes.push_back(disk_drive);
2629 _total_free_4k_blocks += i->blocks;
2634 if (0 == _total_free_4k_blocks) {
2635 strncpy (disk_drive, path().c_str(), 3);
2638 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2640 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2641 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2642 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2649 Session::get_best_session_directory_for_new_audio ()
2651 vector<space_and_path>::iterator i;
2652 string result = _session_dir->root_path();
2654 /* handle common case without system calls */
2656 if (session_dirs.size() == 1) {
2660 /* OK, here's the algorithm we're following here:
2662 We want to select which directory to use for
2663 the next file source to be created. Ideally,
2664 we'd like to use a round-robin process so as to
2665 get maximum performance benefits from splitting
2666 the files across multiple disks.
2668 However, in situations without much diskspace, an
2669 RR approach may end up filling up a filesystem
2670 with new files while others still have space.
2671 Its therefore important to pay some attention to
2672 the freespace in the filesystem holding each
2673 directory as well. However, if we did that by
2674 itself, we'd keep creating new files in the file
2675 system with the most space until it was as full
2676 as all others, thus negating any performance
2677 benefits of this RAID-1 like approach.
2679 So, we use a user-configurable space threshold. If
2680 there are at least 2 filesystems with more than this
2681 much space available, we use RR selection between them.
2682 If not, then we pick the filesystem with the most space.
2684 This gets a good balance between the two
2688 refresh_disk_space ();
2690 int free_enough = 0;
2692 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2693 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2698 if (free_enough >= 2) {
2699 /* use RR selection process, ensuring that the one
2703 i = last_rr_session_dir;
2706 if (++i == session_dirs.end()) {
2707 i = session_dirs.begin();
2710 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2711 SessionDirectory sdir(i->path);
2712 if (sdir.create ()) {
2714 last_rr_session_dir = i;
2719 } while (i != last_rr_session_dir);
2723 /* pick FS with the most freespace (and that
2724 seems to actually work ...)
2727 vector<space_and_path> sorted;
2728 space_and_path_ascending_cmp cmp;
2730 sorted = session_dirs;
2731 sort (sorted.begin(), sorted.end(), cmp);
2733 for (i = sorted.begin(); i != sorted.end(); ++i) {
2734 SessionDirectory sdir(i->path);
2735 if (sdir.create ()) {
2737 last_rr_session_dir = i;
2747 Session::automation_dir () const
2749 return Glib::build_filename (_path, automation_dir_name);
2753 Session::analysis_dir () const
2755 return Glib::build_filename (_path, analysis_dir_name);
2759 Session::plugins_dir () const
2761 return Glib::build_filename (_path, plugins_dir_name);
2765 Session::externals_dir () const
2767 return Glib::build_filename (_path, externals_dir_name);
2771 Session::load_bundles (XMLNode const & node)
2773 XMLNodeList nlist = node.children();
2774 XMLNodeConstIterator niter;
2778 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2779 if ((*niter)->name() == "InputBundle") {
2780 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2781 } else if ((*niter)->name() == "OutputBundle") {
2782 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2784 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2793 Session::load_route_groups (const XMLNode& node, int version)
2795 XMLNodeList nlist = node.children();
2796 XMLNodeConstIterator niter;
2800 if (version >= 3000) {
2802 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2803 if ((*niter)->name() == "RouteGroup") {
2804 RouteGroup* rg = new RouteGroup (*this, "");
2805 add_route_group (rg);
2806 rg->set_state (**niter, version);
2810 } else if (version < 3000) {
2812 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2813 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2814 RouteGroup* rg = new RouteGroup (*this, "");
2815 add_route_group (rg);
2816 rg->set_state (**niter, version);
2825 state_file_filter (const string &str, void* /*arg*/)
2827 return (str.length() > strlen(statefile_suffix) &&
2828 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2832 remove_end(string state)
2834 string statename(state);
2836 string::size_type start,end;
2837 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2838 statename = statename.substr (start+1);
2841 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2842 end = statename.length();
2845 return string(statename.substr (0, end));
2849 Session::possible_states (string path)
2851 vector<string> states;
2852 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2854 transform(states.begin(), states.end(), states.begin(), remove_end);
2856 sort (states.begin(), states.end());
2862 Session::possible_states () const
2864 return possible_states(_path);
2868 Session::new_route_group (const std::string& name)
2870 RouteGroup* rg = NULL;
2872 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2873 if ((*i)->name () == name) {
2880 rg = new RouteGroup (*this, name);
2881 add_route_group (rg);
2887 Session::add_route_group (RouteGroup* g)
2889 _route_groups.push_back (g);
2890 route_group_added (g); /* EMIT SIGNAL */
2892 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2893 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2894 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2900 Session::remove_route_group (RouteGroup& rg)
2902 list<RouteGroup*>::iterator i;
2904 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2905 _route_groups.erase (i);
2908 route_group_removed (); /* EMIT SIGNAL */
2912 /** Set a new order for our route groups, without adding or removing any.
2913 * @param groups Route group list in the new order.
2916 Session::reorder_route_groups (list<RouteGroup*> groups)
2918 _route_groups = groups;
2920 route_groups_reordered (); /* EMIT SIGNAL */
2926 Session::route_group_by_name (string name)
2928 list<RouteGroup *>::iterator i;
2930 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2931 if ((*i)->name() == name) {
2939 Session::all_route_group() const
2941 return *_all_route_group;
2945 Session::add_commands (vector<Command*> const & cmds)
2947 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2953 Session::add_command (Command* const cmd)
2955 assert (_current_trans);
2956 DEBUG_UNDO_HISTORY (
2957 string_compose ("Current Undo Transaction %1, adding command: %2",
2958 _current_trans->name (),
2960 _current_trans->add_command (cmd);
2963 PBD::StatefulDiffCommand*
2964 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2966 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2972 Session::begin_reversible_command (const string& name)
2974 begin_reversible_command (g_quark_from_string (name.c_str ()));
2977 /** Begin a reversible command using a GQuark to identify it.
2978 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2979 * but there must be as many begin...()s as there are commit...()s.
2982 Session::begin_reversible_command (GQuark q)
2984 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2985 to hold all the commands that are committed. This keeps the order of
2986 commands correct in the history.
2989 if (_current_trans == 0) {
2990 DEBUG_UNDO_HISTORY (string_compose (
2991 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2993 /* start a new transaction */
2994 assert (_current_trans_quarks.empty ());
2995 _current_trans = new UndoTransaction();
2996 _current_trans->set_name (g_quark_to_string (q));
2998 DEBUG_UNDO_HISTORY (
2999 string_compose ("Begin Reversible Command, current transaction: %1",
3000 _current_trans->name ()));
3003 _current_trans_quarks.push_front (q);
3007 Session::abort_reversible_command ()
3009 if (_current_trans != 0) {
3010 DEBUG_UNDO_HISTORY (
3011 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
3012 _current_trans->clear();
3013 delete _current_trans;
3015 _current_trans_quarks.clear();
3020 Session::commit_reversible_command (Command *cmd)
3022 assert (_current_trans);
3023 assert (!_current_trans_quarks.empty ());
3028 DEBUG_UNDO_HISTORY (
3029 string_compose ("Current Undo Transaction %1, adding command: %2",
3030 _current_trans->name (),
3032 _current_trans->add_command (cmd);
3035 DEBUG_UNDO_HISTORY (
3036 string_compose ("Commit Reversible Command, current transaction: %1",
3037 _current_trans->name ()));
3039 _current_trans_quarks.pop_front ();
3041 if (!_current_trans_quarks.empty ()) {
3042 DEBUG_UNDO_HISTORY (
3043 string_compose ("Commit Reversible Command, transaction is not "
3044 "top-level, current transaction: %1",
3045 _current_trans->name ()));
3046 /* the transaction we're committing is not the top-level one */
3050 if (_current_trans->empty()) {
3051 /* no commands were added to the transaction, so just get rid of it */
3052 DEBUG_UNDO_HISTORY (
3053 string_compose ("Commit Reversible Command, No commands were "
3054 "added to current transaction: %1",
3055 _current_trans->name ()));
3056 delete _current_trans;
3061 gettimeofday (&now, 0);
3062 _current_trans->set_timestamp (now);
3064 _history.add (_current_trans);
3069 accept_all_audio_files (const string& path, void* /*arg*/)
3071 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3075 if (!AudioFileSource::safe_audio_file_extension (path)) {
3083 accept_all_midi_files (const string& path, void* /*arg*/)
3085 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3089 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3090 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3091 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3095 accept_all_state_files (const string& path, void* /*arg*/)
3097 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3101 std::string const statefile_ext (statefile_suffix);
3102 if (path.length() >= statefile_ext.length()) {
3103 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3110 Session::find_all_sources (string path, set<string>& result)
3115 if (!tree.read (path)) {
3119 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3124 XMLNodeConstIterator niter;
3126 nlist = node->children();
3130 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3132 XMLProperty const * prop;
3134 if ((prop = (*niter)->property (X_("type"))) == 0) {
3138 DataType type (prop->value());
3140 if ((prop = (*niter)->property (X_("name"))) == 0) {
3144 if (Glib::path_is_absolute (prop->value())) {
3145 /* external file, ignore */
3153 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3154 result.insert (found_path);
3162 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3164 vector<string> state_files;
3166 string this_snapshot_path;
3172 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3173 ripped = ripped.substr (0, ripped.length() - 1);
3176 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3178 if (state_files.empty()) {
3183 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3184 this_snapshot_path += statefile_suffix;
3186 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3188 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3190 if (exclude_this_snapshot && *i == this_snapshot_path) {
3191 cerr << "\texcluded\n";
3196 if (find_all_sources (*i, result) < 0) {
3204 struct RegionCounter {
3205 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3206 AudioSourceList::iterator iter;
3207 boost::shared_ptr<Region> region;
3210 RegionCounter() : count (0) {}
3214 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3216 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3217 return r.get_value_or (1);
3221 Session::cleanup_regions ()
3223 bool removed = false;
3224 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3226 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3228 uint32_t used = _playlists->region_use_count (i->second);
3230 if (used == 0 && !i->second->automatic ()) {
3231 boost::weak_ptr<Region> w = i->second;
3234 RegionFactory::map_remove (w);
3241 // re-check to remove parent references of compound regions
3242 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3243 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3247 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3248 if (0 == _playlists->region_use_count (i->second)) {
3249 boost::weak_ptr<Region> w = i->second;
3251 RegionFactory::map_remove (w);
3258 /* dump the history list */
3265 Session::can_cleanup_peakfiles () const
3267 if (deletion_in_progress()) {
3270 if (!_writable || cannot_save ()) {
3271 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3274 if (record_status() == Recording) {
3275 error << _("Cannot cleanup peak-files while recording") << endmsg;
3282 Session::cleanup_peakfiles ()
3284 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3289 assert (can_cleanup_peakfiles ());
3290 assert (!peaks_cleanup_in_progres());
3292 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3294 int timeout = 5000; // 5 seconds
3295 while (!SourceFactory::files_with_peaks.empty()) {
3296 Glib::usleep (1000);
3297 if (--timeout < 0) {
3298 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3299 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3304 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3305 boost::shared_ptr<AudioSource> as;
3306 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3307 as->close_peakfile();
3311 PBD::clear_directory (session_directory().peak_path());
3313 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3315 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3316 boost::shared_ptr<AudioSource> as;
3317 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3318 SourceFactory::setup_peakfile(as, true);
3325 Session::cleanup_sources (CleanupReport& rep)
3327 // FIXME: needs adaptation to midi
3329 vector<boost::shared_ptr<Source> > dead_sources;
3332 vector<string> candidates;
3333 vector<string> unused;
3334 set<string> sources_used_by_all_snapshots;
3341 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3343 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
3345 /* this is mostly for windows which doesn't allow file
3346 * renaming if the file is in use. But we don't special
3347 * case it because we need to know if this causes
3348 * problems, and the easiest way to notice that is to
3349 * keep it in place for all platforms.
3352 request_stop (false);
3354 _butler->wait_until_finished ();
3356 /* consider deleting all unused playlists */
3358 if (_playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3363 /* sync the "all regions" property of each playlist with its current state */
3365 _playlists->sync_all_regions_with_regions ();
3367 /* find all un-used sources */
3372 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3374 SourceMap::iterator tmp;
3379 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3383 if (!i->second->used() && (i->second->length(i->second->natural_position()) > 0)) {
3384 dead_sources.push_back (i->second);
3385 i->second->drop_references ();
3391 /* build a list of all the possible audio directories for the session */
3393 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3394 SessionDirectory sdir ((*i).path);
3395 asp += sdir.sound_path();
3397 audio_path += asp.to_string();
3400 /* build a list of all the possible midi directories for the session */
3402 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3403 SessionDirectory sdir ((*i).path);
3404 msp += sdir.midi_path();
3406 midi_path += msp.to_string();
3408 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3409 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3411 /* add sources from all other snapshots as "used", but don't use this
3412 snapshot because the state file on disk still references sources we
3413 may have already dropped.
3416 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3418 /* Although the region factory has a list of all regions ever created
3419 * for this session, we're only interested in regions actually in
3420 * playlists right now. So merge all playlist regions lists together.
3422 * This will include the playlists used within compound regions.
3425 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3427 /* add our current source list
3430 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3431 boost::shared_ptr<FileSource> fs;
3432 SourceMap::iterator tmp = i;
3435 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3441 /* this is mostly for windows which doesn't allow file
3442 * renaming if the file is in use. But we do not special
3443 * case it because we need to know if this causes
3444 * problems, and the easiest way to notice that is to
3445 * keep it in place for all platforms.
3450 if (!fs->is_stub()) {
3452 /* Note that we're checking a list of all
3453 * sources across all snapshots with the list
3454 * of sources used by this snapshot.
3457 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3458 /* this source is in use by this snapshot */
3459 sources_used_by_all_snapshots.insert (fs->path());
3460 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3462 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3463 /* this source is NOT in use by this snapshot */
3465 /* remove all related regions from RegionFactory master list */
3467 RegionFactory::remove_regions_using_source (i->second);
3469 /* remove from our current source list
3470 * also. We may not remove it from
3471 * disk, because it may be used by
3472 * other snapshots, but it isn't used inside this
3473 * snapshot anymore, so we don't need a
3484 /* now check each candidate source to see if it exists in the list of
3485 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3488 cerr << "Candidates: " << candidates.size() << endl;
3489 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3491 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3496 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3498 tmppath1 = canonical_path (spath);
3499 tmppath2 = canonical_path ((*i));
3501 cerr << "\t => " << tmppath2 << endl;
3503 if (tmppath1 == tmppath2) {
3510 unused.push_back (spath);
3514 cerr << "Actually unused: " << unused.size() << endl;
3516 if (unused.empty()) {
3522 /* now try to move all unused files into the "dead" directory(ies) */
3524 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3529 /* don't move the file across filesystems, just
3530 * stick it in the `dead_dir_name' directory
3531 * on whichever filesystem it was already on.
3534 if ((*x).find ("/sounds/") != string::npos) {
3536 /* old school, go up 1 level */
3538 newpath = Glib::path_get_dirname (*x); // "sounds"
3539 newpath = Glib::path_get_dirname (newpath); // "session-name"
3543 /* new school, go up 4 levels */
3545 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3546 newpath = Glib::path_get_dirname (newpath); // "session-name"
3547 newpath = Glib::path_get_dirname (newpath); // "interchange"
3548 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3551 newpath = Glib::build_filename (newpath, dead_dir_name);
3553 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3554 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3558 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3560 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3562 /* the new path already exists, try versioning */
3564 char buf[PATH_MAX+1];
3568 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3571 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3572 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3576 if (version == 999) {
3577 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3581 newpath = newpath_v;
3586 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3587 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3588 newpath, g_strerror (errno)) << endmsg;
3592 /* see if there an easy to find peakfile for this file, and remove it. */
3594 string base = Glib::path_get_basename (*x);
3595 base += "%A"; /* this is what we add for the channel suffix of all native files,
3596 * or for the first channel of embedded files. it will miss
3597 * some peakfiles for other channels
3599 string peakpath = construct_peak_filepath (base);
3601 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3602 if (::g_unlink (peakpath.c_str ()) != 0) {
3603 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3604 g_strerror (errno)) << endmsg;
3605 /* try to back out */
3606 ::g_rename (newpath.c_str (), _path.c_str ());
3611 rep.paths.push_back (*x);
3612 rep.space += statbuf.st_size;
3615 /* dump the history list */
3619 /* save state so we don't end up a session file
3620 * referring to non-existent sources.
3627 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
3633 Session::cleanup_trash_sources (CleanupReport& rep)
3635 // FIXME: needs adaptation for MIDI
3637 vector<space_and_path>::iterator i;
3643 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3645 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3647 clear_directory (dead_dir, &rep.space, &rep.paths);
3654 Session::set_dirty ()
3656 /* return early if there's nothing to do */
3661 /* never mark session dirty during loading */
3662 if (loading () || deletion_in_progress ()) {
3666 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3667 DirtyChanged(); /* EMIT SIGNAL */
3671 Session::set_clean ()
3673 bool was_dirty = dirty();
3675 _state_of_the_state = Clean;
3678 DirtyChanged(); /* EMIT SIGNAL */
3683 Session::unset_dirty (bool emit_dirty_changed)
3685 bool was_dirty = dirty();
3687 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Dirty));
3689 if (was_dirty && emit_dirty_changed) {
3690 DirtyChanged (); /* EMIT SIGNAL */
3695 Session::set_deletion_in_progress ()
3697 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3701 Session::clear_deletion_in_progress ()
3703 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3707 Session::add_controllable (boost::shared_ptr<Controllable> c)
3709 /* this adds a controllable to the list managed by the Session.
3710 this is a subset of those managed by the Controllable class
3711 itself, and represents the only ones whose state will be saved
3712 as part of the session.
3715 Glib::Threads::Mutex::Lock lm (controllables_lock);
3716 controllables.insert (c);
3719 boost::shared_ptr<Controllable>
3720 Session::controllable_by_id (const PBD::ID& id)
3722 Glib::Threads::Mutex::Lock lm (controllables_lock);
3724 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3725 if ((*i)->id() == id) {
3730 return boost::shared_ptr<Controllable>();
3733 boost::shared_ptr<AutomationControl>
3734 Session::automation_control_by_id (const PBD::ID& id)
3736 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3740 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3743 Stateful::add_instant_xml (node, _path);
3746 if (write_to_config) {
3747 Config->add_instant_xml (node);
3752 Session::instant_xml (const string& node_name)
3754 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3755 if (get_disable_all_loaded_plugins ()) {
3759 return Stateful::instant_xml (node_name, _path);
3763 Session::save_history (string snapshot_name)
3771 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3772 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3776 if (snapshot_name.empty()) {
3777 snapshot_name = _current_snapshot_name;
3780 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3781 const string backup_filename = history_filename + backup_suffix;
3782 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3783 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3785 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3786 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3787 error << _("could not backup old history file, current history not saved") << endmsg;
3792 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3794 if (!tree.write (xml_path))
3796 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3798 if (g_remove (xml_path.c_str()) != 0) {
3799 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3800 xml_path, g_strerror (errno)) << endmsg;
3802 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3803 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3804 backup_path, g_strerror (errno)) << endmsg;
3814 Session::restore_history (string snapshot_name)
3818 if (snapshot_name.empty()) {
3819 snapshot_name = _current_snapshot_name;
3822 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3823 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3825 info << "Loading history from " << xml_path << endmsg;
3827 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3828 info << string_compose (_("%1: no history file \"%2\" for this session."),
3829 _name, xml_path) << endmsg;
3833 if (!tree.read (xml_path)) {
3834 error << string_compose (_("Could not understand session history file \"%1\""),
3835 xml_path) << endmsg;
3842 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3850 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3851 !t->get_property ("tv-usec", tv_usec)) {
3855 UndoTransaction* ut = new UndoTransaction ();
3856 ut->set_name (name);
3860 tv.tv_usec = tv_usec;
3861 ut->set_timestamp(tv);
3863 for (XMLNodeConstIterator child_it = t->children().begin();
3864 child_it != t->children().end(); child_it++)
3866 XMLNode *n = *child_it;
3869 if (n->name() == "MementoCommand" ||
3870 n->name() == "MementoUndoCommand" ||
3871 n->name() == "MementoRedoCommand") {
3873 if ((c = memento_command_factory(n))) {
3877 } else if (n->name() == "NoteDiffCommand") {
3878 PBD::ID id (n->property("midi-source")->value());
3879 boost::shared_ptr<MidiSource> midi_source =
3880 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3882 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3884 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3887 } else if (n->name() == "SysExDiffCommand") {
3889 PBD::ID id (n->property("midi-source")->value());
3890 boost::shared_ptr<MidiSource> midi_source =
3891 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3893 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3895 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3898 } else if (n->name() == "PatchChangeDiffCommand") {
3900 PBD::ID id (n->property("midi-source")->value());
3901 boost::shared_ptr<MidiSource> midi_source =
3902 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3904 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3906 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3909 } else if (n->name() == "StatefulDiffCommand") {
3910 if ((c = stateful_diff_command_factory (n))) {
3911 ut->add_command (c);
3914 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3925 Session::config_changed (std::string p, bool ours)
3931 if (p == "auto-loop") {
3933 } else if (p == "session-monitoring") {
3935 } else if (p == "auto-input") {
3937 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3938 /* auto-input only makes a difference if we're rolling */
3939 set_track_monitor_input_status (!config.get_auto_input());
3942 } else if (p == "punch-in") {
3946 if ((location = _locations->auto_punch_location()) != 0) {
3948 if (config.get_punch_in ()) {
3949 auto_punch_start_changed (location);
3951 clear_events (SessionEvent::PunchIn);
3955 } else if (p == "punch-out") {
3959 if ((location = _locations->auto_punch_location()) != 0) {
3961 if (config.get_punch_out()) {
3962 auto_punch_end_changed (location);
3964 clear_events (SessionEvent::PunchOut);
3968 } else if (p == "edit-mode") {
3970 Glib::Threads::Mutex::Lock lm (_playlists->lock);
3972 for (SessionPlaylists::List::iterator i = _playlists->playlists.begin(); i != _playlists->playlists.end(); ++i) {
3973 (*i)->set_edit_mode (Config->get_edit_mode ());
3976 } else if (p == "use-video-sync") {
3978 waiting_for_sync_offset = config.get_use_video_sync();
3980 } else if (p == "mmc-control") {
3982 //poke_midi_thread ();
3984 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3986 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3988 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3990 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3992 } else if (p == "midi-control") {
3994 //poke_midi_thread ();
3996 } else if (p == "raid-path") {
3998 setup_raid_path (config.get_raid_path());
4000 } else if (p == "timecode-format") {
4004 } else if (p == "video-pullup") {
4008 } else if (p == "seamless-loop") {
4010 if (play_loop && transport_rolling()) {
4011 // to reset diskstreams etc
4012 request_play_loop (true);
4015 } else if (p == "click-sound") {
4017 setup_click_sounds (1);
4019 } else if (p == "click-emphasis-sound") {
4021 setup_click_sounds (-1);
4023 } else if (p == "clicking") {
4025 if (Config->get_clicking()) {
4026 if (_click_io && click_data) { // don't require emphasis data
4033 } else if (p == "click-record-only") {
4035 _click_rec_only = Config->get_click_record_only();
4037 } else if (p == "click-gain") {
4040 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4043 } else if (p == "send-mtc") {
4045 if (Config->get_send_mtc ()) {
4046 /* mark us ready to send */
4047 next_quarter_frame_to_send = 0;
4050 } else if (p == "send-mmc") {
4052 _mmc->enable_send (Config->get_send_mmc ());
4053 if (Config->get_send_mmc ()) {
4054 /* re-initialize MMC */
4055 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4056 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4059 } else if (p == "jack-time-master") {
4061 engine().reset_timebase ();
4063 } else if (p == "native-file-header-format") {
4065 if (!first_file_header_format_reset) {
4066 reset_native_file_format ();
4069 first_file_header_format_reset = false;
4071 } else if (p == "native-file-data-format") {
4073 if (!first_file_data_format_reset) {
4074 reset_native_file_format ();
4077 first_file_data_format_reset = false;
4079 } else if (p == "external-sync") {
4080 request_sync_source (TransportMasterManager::instance().current());
4081 } else if (p == "denormal-model") {
4083 } else if (p == "history-depth") {
4084 set_history_depth (Config->get_history_depth());
4085 } else if (p == "remote-model") {
4086 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4089 } else if (p == "initial-program-change") {
4091 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4094 buf[0] = MIDI::program; // channel zero by default
4095 buf[1] = (Config->get_initial_program_change() & 0x7f);
4097 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4099 } else if (p == "solo-mute-override") {
4100 // catch_up_on_solo_mute_override ();
4101 } else if (p == "listen-position" || p == "pfl-position") {
4102 listen_position_changed ();
4103 } else if (p == "solo-control-is-listen-control") {
4104 solo_control_mode_changed ();
4105 } else if (p == "solo-mute-gain") {
4106 _solo_cut_control->Changed (true, Controllable::NoGroup);
4107 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4108 last_timecode_valid = false;
4109 } else if (p == "playback-buffer-seconds") {
4110 AudioSource::allocate_working_buffers (sample_rate());
4111 } else if (p == "ltc-sink-port") {
4112 reconnect_ltc_output ();
4113 } else if (p == "timecode-generator-offset") {
4114 ltc_tx_parse_offset();
4115 } else if (p == "auto-return-target-list") {
4117 follow_playhead_priority ();
4119 } else if (p == "use-monitor-bus") {
4120 /* NB. This is always called when constructing a session,
4121 * after restoring session state (if any),
4122 * via post_engine_init() -> Config->map_parameters()
4124 bool want_ms = Config->get_use_monitor_bus();
4125 bool have_ms = _monitor_out ? true : false;
4127 /* When loading an existing session, the config "use-monitor-bus"
4128 * is ignored. Instead the sesion-state (xml) will have added the
4129 * "monitor-route" and restored its state (and connections)
4130 * if the session has a monitor-section.
4131 * Update the config to reflect this.
4133 if (want_ms != have_ms) {
4134 Config->set_use_monitor_bus (have_ms);
4136 MonitorBusAddedOrRemoved (); /* EMIT SIGNAL */
4138 /* Otherwise, Config::set_use_monitor_bus() does
4139 * control the the presence of the monitor-section
4140 * (new sessions, user initiated change)
4142 if (want_ms && !have_ms) {
4143 add_monitor_section ();
4144 } else if (!want_ms && have_ms) {
4145 remove_monitor_section ();
4154 Session::set_history_depth (uint32_t d)
4156 _history.set_depth (d);
4159 /** Connect things to the MMC object */
4161 Session::setup_midi_machine_control ()
4163 _mmc = new MIDI::MachineControl;
4165 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4166 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4168 if (!async_out || !async_out) {
4172 /* XXXX argh, passing raw pointers back into libmidi++ */
4174 MIDI::Port* mmc_in = async_in.get();
4175 MIDI::Port* mmc_out = async_out.get();
4177 _mmc->set_ports (mmc_in, mmc_out);
4179 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4180 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4181 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4182 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4183 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4184 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4185 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4186 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4187 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4188 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4189 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4190 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4191 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4193 /* also handle MIDI SPP because its so common */
4195 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4196 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4197 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4200 boost::shared_ptr<Controllable>
4201 Session::solo_cut_control() const
4203 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4204 * controls in Ardour that currently get presented to the user in the GUI that require
4205 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4207 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4208 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4211 return _solo_cut_control;
4215 Session::save_snapshot_name (const std::string & n)
4217 /* assure Stateful::_instant_xml is loaded
4218 * add_instant_xml() only adds to existing data and defaults
4219 * to use an empty Tree otherwise
4221 instant_xml ("LastUsedSnapshot");
4223 XMLNode last_used_snapshot ("LastUsedSnapshot");
4224 last_used_snapshot.set_property ("name", n);
4225 add_instant_xml (last_used_snapshot, false);
4229 Session::set_snapshot_name (const std::string & n)
4231 _current_snapshot_name = n;
4232 save_snapshot_name (n);
4236 Session::rename (const std::string& new_name)
4238 string legal_name = legalize_for_path (new_name);
4244 string const old_sources_root = _session_dir->sources_root();
4246 if (!_writable || cannot_save ()) {
4247 error << _("Cannot rename read-only session.") << endmsg;
4248 return 0; // don't show "messed up" warning
4250 if (record_status() == Recording) {
4251 error << _("Cannot rename session while recording") << endmsg;
4252 return 0; // don't show "messed up" warning
4255 StateProtector stp (this);
4260 * interchange subdirectory
4264 * Backup files are left unchanged and not renamed.
4267 /* Windows requires that we close all files before attempting the
4268 * rename. This works on other platforms, but isn't necessary there.
4269 * Leave it in place for all platforms though, since it may help
4270 * catch issues that could arise if the way Source files work ever
4271 * change (since most developers are not using Windows).
4274 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4275 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4281 /* pass one: not 100% safe check that the new directory names don't
4285 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4289 /* this is a stupid hack because Glib::path_get_dirname() is
4290 * lexical-only, and so passing it /a/b/c/ gives a different
4291 * result than passing it /a/b/c ...
4294 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4295 oldstr = oldstr.substr (0, oldstr.length() - 1);
4298 string base = Glib::path_get_dirname (oldstr);
4300 newstr = Glib::build_filename (base, legal_name);
4302 cerr << "Looking for " << newstr << endl;
4304 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4305 cerr << " exists\n";
4314 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4320 /* this is a stupid hack because Glib::path_get_dirname() is
4321 * lexical-only, and so passing it /a/b/c/ gives a different
4322 * result than passing it /a/b/c ...
4325 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4326 oldstr = oldstr.substr (0, oldstr.length() - 1);
4329 string base = Glib::path_get_dirname (oldstr);
4330 newstr = Glib::build_filename (base, legal_name);
4332 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4334 cerr << "Rename " << oldstr << " => " << newstr << endl;
4335 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4336 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4337 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4341 /* Reset path in "session dirs" */
4346 /* reset primary SessionDirectory object */
4349 (*_session_dir) = newstr;
4354 /* now rename directory below session_dir/interchange */
4356 string old_interchange_dir;
4357 string new_interchange_dir;
4359 /* use newstr here because we renamed the path
4360 * (folder/directory) that used to be oldstr to newstr above
4363 v.push_back (newstr);
4364 v.push_back (interchange_dir_name);
4365 v.push_back (Glib::path_get_basename (oldstr));
4367 old_interchange_dir = Glib::build_filename (v);
4370 v.push_back (newstr);
4371 v.push_back (interchange_dir_name);
4372 v.push_back (legal_name);
4374 new_interchange_dir = Glib::build_filename (v);
4376 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4378 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4379 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4380 old_interchange_dir, new_interchange_dir,
4383 error << string_compose (_("renaming %s as %2 failed (%3)"),
4384 old_interchange_dir, new_interchange_dir,
4393 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4394 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4396 cerr << "Rename " << oldstr << " => " << newstr << endl;
4398 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4399 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4400 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4406 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4408 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4409 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4411 cerr << "Rename " << oldstr << " => " << newstr << endl;
4413 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4414 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4415 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4420 /* remove old name from recent sessions */
4421 remove_recent_sessions (_path);
4424 /* update file source paths */
4426 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4427 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4429 string p = fs->path ();
4430 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4432 SourceFactory::setup_peakfile(i->second, true);
4436 set_snapshot_name (new_name);
4441 /* save state again to get everything just right */
4443 save_state (_current_snapshot_name);
4445 /* add to recent sessions */
4447 store_recent_sessions (new_name, _path);
4453 Session::parse_stateful_loading_version (const std::string& version)
4455 if (version.empty ()) {
4456 /* no version implies very old version of Ardour */
4460 if (version.find ('.') != string::npos) {
4461 /* old school version format */
4462 if (version[0] == '2') {
4468 return string_to<int32_t>(version);
4473 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4475 bool found_sr = false;
4476 bool found_data_format = false;
4477 std::string version;
4478 program_version = "";
4480 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4484 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4488 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4491 xmlFreeParserCtxt(ctxt);
4495 xmlNodePtr node = xmlDocGetRootElement(doc);
4498 xmlFreeParserCtxt(ctxt);
4503 /* sample rate & version*/
4506 for (attr = node->properties; attr; attr = attr->next) {
4507 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4508 version = std::string ((char*)attr->children->content);
4510 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4511 sample_rate = atoi ((char*)attr->children->content);
4516 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4520 node = node->children;
4521 while (node != NULL) {
4522 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4523 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4525 program_version = string ((const char*)val);
4526 size_t sep = program_version.find_first_of("-");
4527 if (sep != string::npos) {
4528 program_version = program_version.substr (0, sep);
4533 if (strcmp((const char*) node->name, "Config")) {
4537 for (node = node->children; node; node = node->next) {
4538 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4539 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4541 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4544 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4546 found_data_format = true;
4547 } catch (PBD::unknown_enumeration& e) {}
4557 xmlFreeParserCtxt(ctxt);
4560 return (found_sr && found_data_format) ? 0 : 1;
4564 Session::get_snapshot_from_instant (const std::string& session_dir)
4566 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4568 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4573 if (!tree.read (instant_xml_path)) {
4577 XMLProperty const * prop;
4578 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4579 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4580 return prop->value();
4586 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4587 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4590 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4594 SourcePathMap source_path_map;
4596 boost::shared_ptr<AudioFileSource> afs;
4601 Glib::Threads::Mutex::Lock lm (source_lock);
4603 cerr << " total sources = " << sources.size();
4605 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4606 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4612 if (fs->within_session()) {
4616 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4617 source_path_map[fs->path()].push_back (fs);
4619 SeveralFileSources v;
4621 source_path_map.insert (make_pair (fs->path(), v));
4627 cerr << " fsources = " << total << endl;
4629 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4631 /* tell caller where we are */
4633 string old_path = i->first;
4635 callback (n, total, old_path);
4637 cerr << old_path << endl;
4641 switch (i->second.front()->type()) {
4642 case DataType::AUDIO:
4643 new_path = new_audio_source_path_for_embedded (old_path);
4646 case DataType::MIDI:
4647 /* XXX not implemented yet */
4651 if (new_path.empty()) {
4655 cerr << "Move " << old_path << " => " << new_path << endl;
4657 if (!copy_file (old_path, new_path)) {
4658 cerr << "failed !\n";
4662 /* make sure we stop looking in the external
4663 dir/folder. Remember, this is an all-or-nothing
4664 operations, it doesn't merge just some files.
4666 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4668 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4669 (*f)->set_path (new_path);
4674 save_state ("", false, false);
4680 bool accept_all_files (string const &, void *)
4686 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4688 /* 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.
4693 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4695 // old_path must be in within_session ()
4696 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4698 v.push_back (new_session_folder); /* full path */
4699 v.push_back (interchange_dir_name);
4700 v.push_back (new_session_name); /* just one directory/folder */
4701 v.push_back (typedir);
4702 v.push_back (Glib::path_get_basename (old_path));
4704 return Glib::build_filename (v);
4708 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4711 v.push_back (new_session_folder); /* full path */
4712 v.push_back (interchange_dir_name);
4713 v.push_back (new_session_name);
4714 v.push_back (ARDOUR::sound_dir_name);
4715 v.push_back (filename);
4717 return Glib::build_filename (v);
4721 Session::save_as (SaveAs& saveas)
4723 vector<string> files;
4724 string current_folder = Glib::path_get_dirname (_path);
4725 string new_folder = legalize_for_path (saveas.new_name);
4726 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4727 int64_t total_bytes = 0;
4731 int32_t internal_file_cnt = 0;
4733 vector<string> do_not_copy_extensions;
4734 do_not_copy_extensions.push_back (statefile_suffix);
4735 do_not_copy_extensions.push_back (pending_suffix);
4736 do_not_copy_extensions.push_back (backup_suffix);
4737 do_not_copy_extensions.push_back (temp_suffix);
4738 do_not_copy_extensions.push_back (history_suffix);
4740 /* get total size */
4742 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4744 /* need to clear this because
4745 * find_files_matching_filter() is cumulative
4750 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4752 all += files.size();
4754 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4756 g_stat ((*i).c_str(), &gsb);
4757 total_bytes += gsb.st_size;
4761 /* save old values so we can switch back if we are not switching to the new session */
4763 string old_path = _path;
4764 string old_name = _name;
4765 string old_snapshot = _current_snapshot_name;
4766 string old_sd = _session_dir->root_path();
4767 vector<string> old_search_path[DataType::num_types];
4768 string old_config_search_path[DataType::num_types];
4770 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4771 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4772 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4773 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4775 /* switch session directory */
4777 (*_session_dir) = to_dir;
4779 /* create new tree */
4781 if (!_session_dir->create()) {
4782 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4787 /* copy all relevant files. Find each location in session_dirs,
4788 * and copy files from there to target.
4791 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4793 /* need to clear this because
4794 * find_files_matching_filter() is cumulative
4799 const size_t prefix_len = (*sd).path.size();
4801 /* Work just on the files within this session dir */
4803 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4805 /* add dir separator to protect against collisions with
4806 * track names (e.g. track named "audiofiles" or
4810 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4811 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4812 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4814 /* copy all the files. Handling is different for media files
4815 than others because of the *silly* subtree we have below the interchange
4816 folder. That really was a bad idea, but I'm not fixing it as part of
4817 implementing ::save_as().
4820 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4822 std::string from = *i;
4825 string filename = Glib::path_get_basename (from);
4826 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4827 if (filename == ".DS_STORE") {
4832 if (from.find (audiofile_dir_string) != string::npos) {
4834 /* audio file: only copy if asked */
4836 if (saveas.include_media && saveas.copy_media) {
4838 string to = make_new_media_path (*i, to_dir, new_folder);
4840 info << "media file copying from " << from << " to " << to << endmsg;
4842 if (!copy_file (from, to)) {
4843 throw Glib::FileError (Glib::FileError::IO_ERROR,
4844 string_compose(_("\ncopying \"%1\" failed !"), from));
4848 /* we found media files inside the session folder */
4850 internal_file_cnt++;
4852 } else if (from.find (midifile_dir_string) != string::npos) {
4854 /* midi file: always copy unless
4855 * creating an empty new session
4858 if (saveas.include_media) {
4860 string to = make_new_media_path (*i, to_dir, new_folder);
4862 info << "media file copying from " << from << " to " << to << endmsg;
4864 if (!copy_file (from, to)) {
4865 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4869 /* we found media files inside the session folder */
4871 internal_file_cnt++;
4873 } else if (from.find (analysis_dir_string) != string::npos) {
4875 /* make sure analysis dir exists in
4876 * new session folder, but we're not
4877 * copying analysis files here, see
4881 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4886 /* normal non-media file. Don't copy state, history, etc.
4889 bool do_copy = true;
4891 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4892 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4893 /* end of filename matches extension, do not copy file */
4899 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4900 /* don't copy peakfiles if
4901 * we're not copying media
4907 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4909 info << "attempting to make directory/folder " << to << endmsg;
4911 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4912 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4915 info << "attempting to copy " << from << " to " << to << endmsg;
4917 if (!copy_file (from, to)) {
4918 throw Glib::FileError (Glib::FileError::IO_ERROR,
4919 string_compose(_("\ncopying \"%1\" failed !"), from));
4924 /* measure file size even if we're not going to copy so that our Progress
4925 signals are correct, since we included these do-not-copy files
4926 in the computation of the total size and file count.
4930 g_stat (from.c_str(), &gsb);
4931 copied += gsb.st_size;
4934 double fraction = (double) copied / total_bytes;
4936 bool keep_going = true;
4938 if (saveas.copy_media) {
4940 /* no need or expectation of this if
4941 * media is not being copied, because
4942 * it will be fast(ish).
4945 /* tell someone "X percent, file M of N"; M is one-based */
4947 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4955 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4961 /* copy optional folders, if any */
4963 string old = plugins_dir ();
4964 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4965 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4966 copy_files (old, newdir);
4969 old = externals_dir ();
4970 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4971 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4972 copy_files (old, newdir);
4975 old = automation_dir ();
4976 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4977 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4978 copy_files (old, newdir);
4981 if (saveas.include_media) {
4983 if (saveas.copy_media) {
4984 #ifndef PLATFORM_WINDOWS
4985 /* There are problems with analysis files on
4986 * Windows, because they used a colon in their
4987 * names as late as 4.0. Colons are not legal
4988 * under Windows even if NTFS allows them.
4990 * This is a tricky problem to solve so for
4991 * just don't copy these files. They will be
4992 * regenerated as-needed anyway, subject to the
4993 * existing issue that the filenames will be
4994 * rejected by Windows, which is a separate
4995 * problem (though related).
4998 /* only needed if we are copying media, since the
4999 * analysis data refers to media data
5002 old = analysis_dir ();
5003 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5004 string newdir = Glib::build_filename (to_dir, "analysis");
5005 copy_files (old, newdir);
5007 #endif /* PLATFORM_WINDOWS */
5012 set_snapshot_name (saveas.new_name);
5013 _name = saveas.new_name;
5015 if (saveas.include_media && !saveas.copy_media) {
5017 /* reset search paths of the new session (which we're pretending to be right now) to
5018 include the original session search path, so we can still find all audio.
5021 if (internal_file_cnt) {
5022 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5023 ensure_search_path_includes (*s, DataType::AUDIO);
5024 cerr << "be sure to include " << *s << " for audio" << endl;
5027 /* we do not do this for MIDI because we copy
5028 all MIDI files if saveas.include_media is
5034 bool was_dirty = dirty ();
5036 save_default_options ();
5038 if (saveas.copy_media && saveas.copy_external) {
5039 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5040 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5044 saveas.final_session_folder_name = _path;
5046 store_recent_sessions (_name, _path);
5048 if (!saveas.switch_to) {
5050 /* save the new state */
5052 save_state ("", false, false, !saveas.include_media);
5054 /* switch back to the way things were */
5058 set_snapshot_name (old_snapshot);
5060 (*_session_dir) = old_sd;
5066 if (internal_file_cnt) {
5067 /* reset these to their original values */
5068 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5069 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5074 /* prune session dirs, and update disk space statistics
5079 session_dirs.clear ();
5080 session_dirs.push_back (sp);
5081 refresh_disk_space ();
5083 _writable = exists_and_writable (_path);
5085 /* ensure that all existing tracks reset their current capture source paths
5087 reset_write_sources (true, true);
5089 /* creating new write sources marks the session as
5090 dirty. If the new session is empty, then
5091 save_state() thinks we're saving a template and will
5092 not mark the session as clean. So do that here,
5093 before we save state.
5096 if (!saveas.include_media) {
5100 save_state ("", false, false, !saveas.include_media);
5102 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5103 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5106 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5107 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5113 if (fs->within_session()) {
5114 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5115 fs->set_path (newpath);
5120 } catch (Glib::FileError& e) {
5122 saveas.failure_message = e.what();
5124 /* recursively remove all the directories */
5126 remove_directory (to_dir);
5134 saveas.failure_message = _("unknown reason");
5136 /* recursively remove all the directories */
5138 remove_directory (to_dir);
5148 static void set_progress (Progress* p, size_t n, size_t t)
5150 p->set_progress (float (n) / float(t));
5154 Session::archive_session (const std::string& dest,
5155 const std::string& name,
5156 ArchiveEncode compress_audio,
5157 FileArchive::CompressionLevel compression_level,
5158 bool only_used_sources,
5161 if (dest.empty () || name.empty ()) {
5165 /* We are going to temporarily change some source properties,
5166 * don't allow any concurrent saves (periodic or otherwise */
5167 Glib::Threads::Mutex::Lock lm (save_source_lock);
5169 disable_record (false);
5171 /* save current values */
5172 string old_path = _path;
5173 string old_name = _name;
5174 string old_snapshot = _current_snapshot_name;
5175 string old_sd = _session_dir->root_path();
5176 string old_config_search_path[DataType::num_types];
5177 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5178 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5180 /* ensure that session-path is included in search-path */
5182 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5183 if ((*sd).path == old_path) {
5191 /* create temporary dir to save session to */
5192 #ifdef PLATFORM_WINDOWS
5193 char tmp[256] = "C:\\TEMP\\";
5194 GetTempPath (sizeof (tmp), tmp);
5196 char const* tmp = getenv("TMPDIR");
5201 if ((strlen (tmp) + 21) > 1024) {
5206 strcpy (tmptpl, tmp);
5207 strcat (tmptpl, "ardourarchive-XXXXXX");
5208 char* tmpdir = g_mkdtemp (tmptpl);
5214 std::string to_dir = std::string (tmpdir);
5216 /* switch session directory temporarily */
5217 (*_session_dir) = to_dir;
5219 if (!_session_dir->create()) {
5220 (*_session_dir) = old_sd;
5221 remove_directory (to_dir);
5225 /* prepare archive */
5226 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5228 PBD::ScopedConnectionList progress_connection;
5229 PBD::FileArchive ar (archive);
5231 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5234 /* collect files to archive */
5235 std::map<string,string> filemap;
5237 vector<string> do_not_copy_extensions;
5238 do_not_copy_extensions.push_back (statefile_suffix);
5239 do_not_copy_extensions.push_back (pending_suffix);
5240 do_not_copy_extensions.push_back (backup_suffix);
5241 do_not_copy_extensions.push_back (temp_suffix);
5242 do_not_copy_extensions.push_back (history_suffix);
5244 vector<string> blacklist_dirs;
5245 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5246 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5247 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5248 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5249 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5250 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5252 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5253 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5254 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5256 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5257 if (only_used_sources) {
5258 _playlists->sync_all_regions_with_regions ();
5259 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5262 /* collect audio sources for this session, calc total size for encoding
5263 * add option to only include *used* sources (see Session::cleanup_sources)
5265 size_t total_size = 0;
5267 Glib::Threads::Mutex::Lock lm (source_lock);
5269 /* build a list of used names */
5270 std::set<std::string> audio_file_names;
5271 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5272 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5275 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5276 if (!afs || afs->readable_length () == 0) {
5279 if (only_used_sources) {
5283 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5287 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5290 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5291 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5294 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5295 if (!afs || afs->readable_length () == 0) {
5299 if (only_used_sources) {
5303 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5308 std::string from = afs->path();
5310 if (compress_audio != NO_ENCODE) {
5311 total_size += afs->readable_length ();
5313 /* copy files as-is */
5314 if (!afs->within_session()) {
5315 string to = Glib::path_get_basename (from);
5317 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5318 * - avoid conflict with files existing in interchange
5319 * - avoid conflict with other embedded sources
5321 if (audio_file_names.find (to) == audio_file_names.end ()) {
5322 // we need a new name, add a '-<num>' before the '.<ext>'
5323 string bn = to.substr (0, to.find_last_of ('.'));
5324 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5325 to = bn + "-1" + ext;
5327 while (audio_file_names.find (to) == audio_file_names.end ()) {
5328 to = bump_name_once (to, '-');
5331 audio_file_names.insert (to);
5332 filemap[from] = make_new_audio_path (to, name, name);
5334 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5336 orig_origin[afs] = afs->origin ();
5337 afs->set_origin ("");
5340 filemap[from] = make_new_media_path (from, name, name);
5347 if (compress_audio != NO_ENCODE) {
5349 progress->set_progress (2); // set to "encoding"
5350 progress->set_progress (0);
5353 Glib::Threads::Mutex::Lock lm (source_lock);
5354 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5355 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5358 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5359 if (!afs || afs->readable_length () == 0) {
5363 if (only_used_sources) {
5367 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5372 orig_sources[afs] = afs->path();
5373 orig_gain[afs] = afs->gain();
5375 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5377 std::string channelsuffix = "";
5378 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5379 /* embedded external multi-channel files are converted to multiple-mono */
5380 channelsuffix = string_compose ("-c%1", afs->channel ());
5382 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5383 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5385 /* avoid name collisions of external files with same name */
5386 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5387 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5389 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5390 new_path = bump_name_once (new_path, '-');
5394 progress->descend ((float)afs->readable_length () / total_size);
5398 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5399 afs->replace_file (new_path);
5400 afs->set_gain (ns->gain(), true);
5403 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5407 progress->ascend ();
5413 progress->set_progress (-1); // set to "archiving"
5414 progress->set_progress (0);
5417 /* index files relevant for this session */
5418 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5419 vector<string> files;
5421 size_t prefix_len = (*sd).path.size();
5422 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5426 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5428 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5429 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5430 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5432 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5433 std::string from = *i;
5436 string filename = Glib::path_get_basename (from);
5437 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5438 if (filename == ".DS_STORE") {
5443 if (from.find (audiofile_dir_string) != string::npos) {
5445 } else if (from.find (midifile_dir_string) != string::npos) {
5446 filemap[from] = make_new_media_path (from, name, name);
5447 } else if (from.find (videofile_dir_string) != string::npos) {
5448 filemap[from] = make_new_media_path (from, name, name);
5450 bool do_copy = true;
5451 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5452 if (from.find (*v) != string::npos) {
5457 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5458 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5465 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5471 /* write session file */
5473 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5475 save_state (name, false, false, false, true, only_used_sources);
5477 save_default_options ();
5479 size_t prefix_len = _path.size();
5480 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5484 /* collect session-state files */
5485 vector<string> files;
5486 do_not_copy_extensions.clear ();
5487 do_not_copy_extensions.push_back (history_suffix);
5489 blacklist_dirs.clear ();
5490 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5492 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5493 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5494 std::string from = *i;
5495 bool do_copy = true;
5496 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5497 if (from.find (*v) != string::npos) {
5502 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5503 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5509 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5513 /* restore original values */
5516 set_snapshot_name (old_snapshot);
5517 (*_session_dir) = old_sd;
5518 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5519 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5521 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5522 i->first->set_origin (i->second);
5524 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5525 i->first->replace_file (i->second);
5527 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5528 i->first->set_gain (i->second, true);
5531 int rv = ar.create (filemap, compression_level);
5532 remove_directory (to_dir);
5538 Session::undo (uint32_t n)
5540 if (actively_recording()) {
5548 Session::redo (uint32_t n)
5550 if (actively_recording()) {