2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
53 #include "pbd/locale_guard.h"
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/basename.h"
67 #include "pbd/debug.h"
68 #include "pbd/enumwriter.h"
69 #include "pbd/error.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/types_convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/audioregion.h"
84 #include "ardour/auditioner.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/boost_debug.h"
87 #include "ardour/butler.h"
88 #include "ardour/controllable_descriptor.h"
89 #include "ardour/control_protocol_manager.h"
90 #include "ardour/directory_names.h"
91 #include "ardour/disk_reader.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/selection.h"
118 #include "ardour/session.h"
119 #include "ardour/session_directory.h"
120 #include "ardour/session_metadata.h"
121 #include "ardour/session_playlists.h"
122 #include "ardour/session_state_utils.h"
123 #include "ardour/silentfilesource.h"
124 #include "ardour/smf_source.h"
125 #include "ardour/sndfilesource.h"
126 #include "ardour/source_factory.h"
127 #include "ardour/speakers.h"
128 #include "ardour/template_utils.h"
129 #include "ardour/tempo.h"
130 #include "ardour/ticker.h"
131 #include "ardour/types_convert.h"
132 #include "ardour/user_bundle.h"
133 #include "ardour/vca.h"
134 #include "ardour/vca_manager.h"
136 #include "control_protocol/control_protocol.h"
138 #include "LuaBridge/LuaBridge.h"
140 #include "pbd/i18n.h"
144 using namespace ARDOUR;
147 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
150 Session::pre_engine_init (string fullpath)
152 if (fullpath.empty()) {
154 throw failed_constructor();
157 /* discover canonical fullpath */
159 _path = canonical_path(fullpath);
162 if (Profile->get_trx() ) {
163 // Waves TracksLive has a usecase of session replacement with a new one.
164 // We should check session state file (<session_name>.ardour) existance
165 // to determine if the session is new or not
167 string full_session_name = Glib::build_filename( fullpath, _name );
168 full_session_name += statefile_suffix;
170 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
172 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
175 /* finish initialization that can't be done in a normal C++ constructor
179 timerclear (&last_mmc_step);
180 g_atomic_int_set (&processing_prohibited, 0);
181 g_atomic_int_set (&_record_status, Disabled);
182 g_atomic_int_set (&_playback_load, 100);
183 g_atomic_int_set (&_capture_load, 100);
185 _all_route_group->set_active (true, this);
186 interpolation.add_channel ();
188 if (config.get_use_video_sync()) {
189 waiting_for_sync_offset = true;
191 waiting_for_sync_offset = false;
194 last_rr_session_dir = session_dirs.begin();
196 set_history_depth (Config->get_history_depth());
198 /* default: assume simple stereo speaker configuration */
200 _speakers->setup_default_speakers (2);
202 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
203 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
204 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
205 add_controllable (_solo_cut_control);
207 /* These are all static "per-class" signals */
209 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
210 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
211 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
212 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
213 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
215 /* stop IO objects from doing stuff until we're ready for them */
217 Delivery::disable_panners ();
218 IO::disable_connecting ();
222 Session::post_engine_init ()
224 BootMessage (_("Set block size and sample rate"));
226 set_block_size (_engine.samples_per_cycle());
227 set_sample_rate (_engine.sample_rate());
229 BootMessage (_("Using configuration"));
231 _midi_ports = new MidiPortManager;
233 MIDISceneChanger* msc;
235 _scene_changer = msc = new MIDISceneChanger (*this);
236 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
237 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
239 boost::function<samplecnt_t(void)> timer_func (boost::bind (&Session::audible_sample, this, (bool*)(0)));
240 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
242 setup_midi_machine_control ();
244 if (_butler->start_thread()) {
245 error << _("Butler did not start") << endmsg;
249 if (start_midi_thread ()) {
250 error << _("MIDI I/O thread did not start") << endmsg;
254 setup_click_sounds (0);
255 setup_midi_control ();
257 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
258 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
261 /* tempo map requires sample rate knowledge */
264 _tempo_map = new TempoMap (_current_sample_rate);
265 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
266 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
267 } catch (std::exception const & e) {
268 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
271 error << _("Unknown exception during session setup") << endmsg;
276 /* MidiClock requires a tempo map */
279 midi_clock = new MidiClockTicker ();
280 midi_clock->set_session (this);
282 /* crossfades require sample rate knowledge */
284 SndFileSource::setup_standard_crossfades (*this, sample_rate());
285 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
286 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
288 DiskReader::allocate_working_buffers();
289 refresh_disk_space ();
291 /* we're finally ready to call set_state() ... all objects have
292 * been created, the engine is running.
297 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
298 error << _("Could not set session state from XML") << endmsg;
301 } catch (PBD::unknown_enumeration& e) {
302 error << _("Session state: ") << e.what() << endmsg;
306 // set_state() will call setup_raid_path(), but if it's a new session we need
307 // to call setup_raid_path() here.
308 setup_raid_path (_path);
313 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
314 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
316 Config->map_parameters (ff);
317 config.map_parameters (ft);
318 _butler->map_parameters ();
320 /* Reset all panners */
322 Delivery::reset_panners ();
324 /* this will cause the CPM to instantiate any protocols that are in use
325 * (or mandatory), which will pass it this Session, and then call
326 * set_state() on each instantiated protocol to match stored state.
329 ControlProtocolManager::instance().set_session (this);
331 /* This must be done after the ControlProtocolManager set_session above,
332 as it will set states for ports which the ControlProtocolManager creates.
335 // XXX set state of MIDI::Port's
336 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
338 /* And this must be done after the MIDI::Manager::set_port_states as
339 * it will try to make connections whose details are loaded by set_port_states.
344 /* Let control protocols know that we are now all connected, so they
345 * could start talking to surfaces if they want to.
348 ControlProtocolManager::instance().midi_connectivity_established ();
350 if (_is_new && !no_auto_connect()) {
351 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
352 auto_connect_master_bus ();
355 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
357 /* update latencies */
359 initialize_latencies ();
361 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
362 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
363 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
365 } catch (AudioEngine::PortRegistrationFailure& err) {
366 error << err.what() << endmsg;
368 } catch (std::exception const & e) {
369 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
372 error << _("Unknown exception during session setup") << endmsg;
376 BootMessage (_("Reset Remote Controls"));
378 // send_full_time_code (0);
379 _engine.transport_locate (0);
381 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
382 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
384 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
387 /* initial program change will be delivered later; see ::config_changed() */
389 _state_of_the_state = Clean;
391 Port::set_connecting_blocked (false);
393 DirtyChanged (); /* EMIT SIGNAL */
397 } else if (state_was_pending) {
399 remove_pending_capture_state ();
400 state_was_pending = false;
403 /* Now, finally, we can fill the playback buffers */
405 BootMessage (_("Filling playback buffers"));
407 boost::shared_ptr<RouteList> rl = routes.reader();
408 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
409 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
410 if (trk && !trk->is_private_route()) {
411 trk->seek (_transport_sample, true);
419 Session::session_loaded ()
423 _state_of_the_state = Clean;
425 DirtyChanged (); /* EMIT SIGNAL */
429 } else if (state_was_pending) {
431 remove_pending_capture_state ();
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 dir = analysis_dir ();
537 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
538 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
542 dir = plugins_dir ();
544 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
545 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
549 dir = externals_dir ();
551 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
552 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
559 /** @param session_template directory containing session template, or empty.
560 * Caller must not hold process lock.
563 Session::create (const string& session_template, BusProfile* bus_profile)
565 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
566 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
570 if (ensure_subdirs ()) {
574 _writable = exists_and_writable (_path);
576 if (!session_template.empty()) {
577 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
579 FILE* in = g_fopen (in_path.c_str(), "rb");
582 /* no need to call legalize_for_path() since the string
583 * in session_template is already a legal path name
585 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
587 FILE* out = g_fopen (out_path.c_str(), "wb");
591 stringstream new_session;
594 size_t charsRead = fread (buf, sizeof(char), 1024, in);
597 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
602 if (charsRead == 0) {
605 new_session.write (buf, charsRead);
609 string file_contents = new_session.str();
610 size_t writeSize = file_contents.length();
611 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
612 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
620 if (!ARDOUR::Profile->get_trx()) {
621 /* Copy plugin state files from template to new session */
622 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
623 copy_recurse (template_plugins, plugins_dir ());
629 error << string_compose (_("Could not open %1 for writing session template"), out_path)
636 error << string_compose (_("Could not open session template %1 for reading"), in_path)
643 if (Profile->get_trx()) {
645 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
646 * Remember that this is a brand new session. Sessions
647 * loaded from saved state will get this range from the saved state.
650 set_session_range_location (0, 0);
652 /* Initial loop location, from absolute zero, length 10 seconds */
654 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
655 _locations->add (loc, true);
656 set_auto_loop_location (loc);
659 _state_of_the_state = Clean;
661 /* set up Master Out and Monitor Out if necessary */
665 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
666 if (bus_profile->master_out_channels) {
667 int rv = add_master_bus (count);
673 if (Config->get_use_monitor_bus())
674 add_monitor_section ();
682 Session::maybe_write_autosave()
684 if (dirty() && record_status() != Recording) {
685 save_state("", true);
690 Session::remove_pending_capture_state ()
692 std::string pending_state_file_path(_session_dir->root_path());
694 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
696 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
698 if (g_remove (pending_state_file_path.c_str()) != 0) {
699 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
700 pending_state_file_path, g_strerror (errno)) << endmsg;
704 /** Rename a state file.
705 * @param old_name Old snapshot name.
706 * @param new_name New snapshot name.
709 Session::rename_state (string old_name, string new_name)
711 if (old_name == _current_snapshot_name || old_name == _name) {
712 /* refuse to rename the current snapshot or the "main" one */
716 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
717 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
719 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
720 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
722 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
723 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
724 old_name, new_name, g_strerror(errno)) << endmsg;
728 /** Remove a state file.
729 * @param snapshot_name Snapshot name.
732 Session::remove_state (string snapshot_name)
734 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
735 // refuse to remove the current snapshot or the "main" one
739 std::string xml_path(_session_dir->root_path());
741 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
743 if (!create_backup_file (xml_path)) {
744 // don't remove it if a backup can't be made
745 // create_backup_file will log the error.
750 if (g_remove (xml_path.c_str()) != 0) {
751 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
752 xml_path, g_strerror (errno)) << endmsg;
756 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
758 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only, bool for_archive, bool only_used_assets)
760 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
763 std::string xml_path(_session_dir->root_path());
765 /* prevent concurrent saves from different threads */
767 Glib::Threads::Mutex::Lock lm (save_state_lock);
768 Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK);
773 if (!_writable || (_state_of_the_state & CannotSave)) {
777 if (g_atomic_int_get(&_suspend_save)) {
781 _save_queued = false;
783 snapshot_t fork_state = NormalSave;
784 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) {
785 /* snapshot, close midi */
786 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
790 const int64_t save_start_time = g_get_monotonic_time();
793 /* tell sources we're saving first, in case they write out to a new file
794 * which should be saved with the state rather than the old one */
795 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
797 i->second->session_saved();
798 } catch (Evoral::SMF::FileError& e) {
799 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
803 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, for_archive);
805 SessionSaveUnderway (); /* EMIT SIGNAL */
807 bool mark_as_clean = true;
808 if (!snapshot_name.empty() && !switch_to_snapshot) {
809 mark_as_clean = false;
813 mark_as_clean = false;
814 tree.set_root (&get_template());
816 tree.set_root (&state (false, fork_state, only_used_assets));
819 if (snapshot_name.empty()) {
820 snapshot_name = _current_snapshot_name;
821 } else if (switch_to_snapshot) {
822 set_snapshot_name (snapshot_name);
825 assert (!snapshot_name.empty());
829 /* proper save: use statefile_suffix (.ardour in English) */
831 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
833 /* make a backup copy of the old file */
835 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
836 // create_backup_file will log the error
842 /* pending save: use pending_suffix (.pending in English) */
843 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
846 std::string tmp_path(_session_dir->root_path());
847 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
850 cerr << "actually writing state to " << tmp_path << endl;
853 if (!tree.write (tmp_path)) {
854 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
855 if (g_remove (tmp_path.c_str()) != 0) {
856 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
857 tmp_path, g_strerror (errno)) << endmsg;
864 cerr << "renaming state to " << xml_path << endl;
867 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
868 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
869 tmp_path, xml_path, g_strerror(errno)) << endmsg;
870 if (g_remove (tmp_path.c_str()) != 0) {
871 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
872 tmp_path, g_strerror (errno)) << endmsg;
878 if (!pending && !for_archive) {
880 save_history (snapshot_name);
883 bool was_dirty = dirty();
885 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
888 DirtyChanged (); /* EMIT SIGNAL */
892 StateSaved (snapshot_name); /* EMIT SIGNAL */
896 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
897 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
903 Session::restore_state (string snapshot_name)
906 if (load_state (snapshot_name) == 0) {
907 set_state (*state_tree->root(), Stateful::loading_state_version);
911 // unknown_enumeration
919 Session::load_state (string snapshot_name)
924 state_was_pending = false;
926 /* check for leftover pending state from a crashed capture attempt */
928 std::string xmlpath(_session_dir->root_path());
929 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
931 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
933 /* there is pending state from a crashed capture attempt */
935 boost::optional<int> r = AskAboutPendingState();
936 if (r.get_value_or (1)) {
937 state_was_pending = true;
941 if (!state_was_pending) {
942 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
945 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
946 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
947 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
948 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
953 state_tree = new XMLTree;
957 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
959 if (!state_tree->read (xmlpath)) {
960 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
966 XMLNode const & root (*state_tree->root());
968 if (root.name() != X_("Session")) {
969 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
976 root.get_property ("version", version);
977 Stateful::loading_state_version = parse_stateful_loading_version (version);
979 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
980 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
981 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
984 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
986 std::string backup_path(_session_dir->root_path());
987 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
988 backup_path = Glib::build_filename (backup_path, backup_filename);
990 // only create a backup for a given statefile version once
992 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
994 VersionMismatch (xmlpath, backup_path);
996 if (!copy_file (xmlpath, backup_path)) {;
1002 save_snapshot_name (snapshot_name);
1008 Session::load_options (const XMLNode& node)
1010 config.set_variables (node);
1015 Session::save_default_options ()
1017 return config.save_state();
1021 Session::get_state ()
1023 /* this is not directly called, but required by PBD::Stateful */
1025 return state (false, NormalSave);
1029 Session::get_template ()
1031 /* if we don't disable rec-enable, diskstreams
1032 will believe they need to store their capture
1033 sources in their state node.
1036 disable_record (false);
1038 return state (true, NormalSave);
1041 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1042 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1045 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1047 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1050 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1054 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1057 XMLNode* node = new XMLNode("TrackState"); // XXX
1060 PlaylistSet playlists; // SessionPlaylists
1063 // these will work with new_route_from_template()
1064 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1065 child = node->add_child ("Routes");
1066 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1067 if ((*i)->is_auditioner()) {
1070 if ((*i)->is_master() || (*i)->is_monitor()) {
1073 child->add_child_nocopy ((*i)->get_state());
1074 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1076 playlists.insert (track->playlist ());
1080 // on load, Regions in the playlists need to resolve and map Source-IDs
1081 // also playlist needs to be merged or created with new-name..
1082 // ... and Diskstream in tracks adjusted to use the correct playlist
1083 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1084 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1085 child->add_child_nocopy ((*i)->get_state ());
1086 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1087 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1088 const Region::SourceList& sl = (*s)->sources ();
1089 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1090 sources.insert (*sli);
1095 child = node->add_child ("Sources");
1096 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1097 child->add_child_nocopy ((*i)->get_state ());
1098 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1100 #ifdef PLATFORM_WINDOWS
1103 string p = fs->path ();
1104 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1108 std::string sn = Glib::build_filename (path, "share.axml");
1111 tree.set_root (node);
1112 return tree.write (sn.c_str());
1116 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
1118 pl->deep_sources (*all_sources);
1123 struct route_id_compare {
1125 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1127 return r1->id () < r2->id ();
1133 Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets)
1136 XMLNode* node = new XMLNode("Session");
1139 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1141 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1143 child = node->add_child ("ProgramVersion");
1144 child->set_property("created-with", created_with);
1146 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1147 child->set_property("modified-with", modified_with);
1149 /* store configuration settings */
1151 if (!save_template) {
1153 node->set_property ("name", _name);
1154 node->set_property ("sample-rate", _base_sample_rate);
1156 if (session_dirs.size() > 1) {
1160 vector<space_and_path>::iterator i = session_dirs.begin();
1161 vector<space_and_path>::iterator next;
1163 ++i; /* skip the first one */
1167 while (i != session_dirs.end()) {
1171 if (next != session_dirs.end()) {
1172 p += G_SEARCHPATH_SEPARATOR;
1181 child = node->add_child ("Path");
1182 child->add_content (p);
1184 node->set_property ("end-is-free", _session_range_end_is_free);
1187 /* save the ID counter */
1189 node->set_property ("id-counter", ID::counter());
1191 node->set_property ("name-counter", name_id_counter ());
1193 /* save the event ID counter */
1195 node->set_property ("event-counter", Evoral::event_id_counter());
1197 /* save the VCA counter */
1199 node->set_property ("vca-counter", VCA::get_next_vca_number());
1201 /* various options */
1203 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1204 if (!midi_port_nodes.empty()) {
1205 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1206 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1207 midi_port_stuff->add_child_nocopy (**n);
1209 node->add_child_nocopy (*midi_port_stuff);
1212 XMLNode& cfgxml (config.get_variables ());
1213 if (save_template) {
1214 /* exclude search-paths from template */
1215 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1216 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1217 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1219 node->add_child_nocopy (cfgxml);
1221 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1223 child = node->add_child ("Sources");
1225 if (!save_template) {
1226 Glib::Threads::Mutex::Lock sl (source_lock);
1228 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1230 if (only_used_assets) {
1231 playlists->sync_all_regions_with_regions ();
1232 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1235 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1237 /* Don't save information about non-file Sources, or
1238 * about non-destructive file sources that are empty
1239 * and unused by any regions.
1241 boost::shared_ptr<FileSource> fs;
1243 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1247 if (!fs->destructive()) {
1248 if (fs->empty() && !fs->used()) {
1253 if (only_used_assets) {
1254 /* skip only unused audio files */
1255 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1256 if (afs && !afs->used()) {
1259 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1264 if (snapshot_type != NormalSave && fs->within_session ()) {
1265 /* copy MIDI sources to new file
1267 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1268 * because the GUI (midi_region) has a direct pointer to the midi-model
1269 * of the source, as does UndoTransaction.
1271 * On the upside, .mid files are not kept open. The file is only open
1272 * when reading the model initially and when flushing the model to disk:
1273 * source->session_saved () or export.
1275 * We can change the _path of the existing source under the hood, keeping
1276 * all IDs, references and pointers intact.
1278 boost::shared_ptr<SMFSource> ms;
1279 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1280 const std::string ancestor_name = ms->ancestor_name();
1281 const std::string base = PBD::basename_nosuffix(ancestor_name);
1282 const string path = new_midi_source_path (base, false);
1284 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1285 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1286 Source::Lock lm (ms->mutex());
1288 // TODO special-case empty, removable() files: just create a new removable.
1289 // (load + write flushes the model and creates the file)
1291 ms->load_model (lm);
1293 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1294 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1296 if (snapshot_type == SnapshotKeep) {
1297 /* keep working on current session.
1299 * Save snapshot-state with the original filename.
1300 * Switch to use new path for future saves of the main session.
1302 child->add_child_nocopy (ms->get_state());
1306 * ~SMFSource unlinks removable() files.
1308 std::string npath (ms->path ());
1309 ms->replace_file (newsrc->path ());
1310 newsrc->replace_file (npath);
1312 if (snapshot_type == SwitchToSnapshot) {
1313 /* save and switch to snapshot.
1315 * Leave the old file in place (as is).
1316 * Snapshot uses new source directly
1318 child->add_child_nocopy (ms->get_state());
1325 child->add_child_nocopy (siter->second->get_state());
1329 child = node->add_child ("Regions");
1331 if (!save_template) {
1332 Glib::Threads::Mutex::Lock rl (region_lock);
1334 if (!only_used_assets) {
1335 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1336 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1337 boost::shared_ptr<Region> r = i->second;
1338 /* only store regions not attached to playlists */
1339 if (r->playlist() == 0) {
1340 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1341 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1343 child->add_child_nocopy (r->get_state ());
1349 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1351 if (!cassocs.empty()) {
1352 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1354 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1355 if (i->first->playlist () == 0 && only_used_assets) {
1358 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1359 can->set_property (X_("copy"), i->first->id());
1360 can->set_property (X_("original"), i->second->id());
1361 ca->add_child_nocopy (*can);
1362 /* see above, child is still "Regions" here */
1363 if (i->second->playlist() == 0 && only_used_assets) {
1364 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1365 child->add_child_nocopy (ar->get_basic_state ());
1367 child->add_child_nocopy (ar->get_state ());
1374 if (!save_template) {
1376 node->add_child_nocopy (_selection->get_state());
1379 node->add_child_nocopy (_locations->get_state());
1382 Locations loc (*this);
1383 const bool was_dirty = dirty();
1384 // for a template, just create a new Locations, populate it
1385 // with the default start and end, and get the state for that.
1386 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1387 range->set (max_samplepos, 0);
1389 XMLNode& locations_state = loc.get_state();
1391 if (ARDOUR::Profile->get_trx() && _locations) {
1392 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1393 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1394 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1395 locations_state.add_child_nocopy ((*i)->get_state ());
1399 node->add_child_nocopy (locations_state);
1401 /* adding a location above will have marked the session
1402 * dirty. This is an artifact, so fix it if the session wasn't
1407 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1411 child = node->add_child ("Bundles");
1413 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1414 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1415 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1417 child->add_child_nocopy (b->get_state());
1422 node->add_child_nocopy (_vca_manager->get_state());
1424 child = node->add_child ("Routes");
1426 boost::shared_ptr<RouteList> r = routes.reader ();
1428 route_id_compare cmp;
1429 RouteList xml_node_order (*r);
1430 xml_node_order.sort (cmp);
1432 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1433 if (!(*i)->is_auditioner()) {
1434 if (save_template) {
1435 child->add_child_nocopy ((*i)->get_template());
1437 child->add_child_nocopy ((*i)->get_state());
1443 playlists->add_state (node, save_template, !only_used_assets);
1445 child = node->add_child ("RouteGroups");
1446 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1447 child->add_child_nocopy ((*i)->get_state());
1451 XMLNode* gain_child = node->add_child ("Click");
1452 gain_child->add_child_nocopy (_click_io->get_state ());
1453 gain_child->add_child_nocopy (_click_gain->get_state ());
1457 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1458 ltc_input_child->add_child_nocopy (_ltc_input->get_state ());
1462 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1463 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1466 node->add_child_nocopy (_speakers->get_state());
1467 node->add_child_nocopy (_tempo_map->get_state());
1468 node->add_child_nocopy (get_control_protocol_state());
1471 node->add_child_copy (*_extra_xml);
1475 Glib::Threads::Mutex::Lock lm (lua_lock);
1478 luabridge::LuaRef savedstate ((*_lua_save)());
1479 saved = savedstate.cast<std::string>();
1481 lua.collect_garbage ();
1484 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1485 std::string b64s (b64);
1488 XMLNode* script_node = new XMLNode (X_("Script"));
1489 script_node->set_property (X_("lua"), LUA_VERSION);
1490 script_node->add_content (b64s);
1491 node->add_child_nocopy (*script_node);
1498 Session::get_control_protocol_state ()
1500 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1501 return cpm.get_state();
1505 Session::set_state (const XMLNode& node, int version)
1512 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1514 if (node.name() != X_("Session")) {
1515 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1519 node.get_property ("name", _name);
1521 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1523 _nominal_sample_rate = _base_sample_rate;
1525 assert (AudioEngine::instance()->running ());
1526 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1527 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1528 if (r.get_value_or (0)) {
1534 created_with = "unknown";
1535 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1536 child->get_property (X_("created-with"), created_with);
1539 setup_raid_path(_session_dir->root_path());
1541 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1544 if (node.get_property (X_("id-counter"), counter)) {
1545 ID::init_counter (counter);
1547 /* old sessions used a timebased counter, so fake
1548 * the startup ID counter based on a standard
1553 ID::init_counter (now);
1556 if (node.get_property (X_("name-counter"), counter)) {
1557 init_name_id_counter (counter);
1560 if (node.get_property (X_("event-counter"), counter)) {
1561 Evoral::init_event_id_counter (counter);
1564 if (node.get_property (X_("vca-counter"), counter)) {
1565 VCA::set_next_vca_number (counter);
1567 VCA::set_next_vca_number (1);
1570 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1571 _midi_ports->set_midi_port_states (child->children());
1574 IO::disable_connecting ();
1576 Stateful::save_extra_xml (node);
1578 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1579 load_options (*child);
1580 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1581 load_options (*child);
1583 error << _("Session: XML state has no options section") << endmsg;
1586 if (version >= 3000) {
1587 if ((child = find_named_node (node, "Metadata")) == 0) {
1588 warning << _("Session: XML state has no metadata section") << endmsg;
1589 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1594 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1595 _speakers->set_state (*child, version);
1598 if ((child = find_named_node (node, "Sources")) == 0) {
1599 error << _("Session: XML state has no sources section") << endmsg;
1601 } else if (load_sources (*child)) {
1605 if ((child = find_named_node (node, "TempoMap")) == 0) {
1606 error << _("Session: XML state has no Tempo Map section") << endmsg;
1608 } else if (_tempo_map->set_state (*child, version)) {
1612 if ((child = find_named_node (node, "Locations")) == 0) {
1613 error << _("Session: XML state has no locations section") << endmsg;
1615 } else if (_locations->set_state (*child, version)) {
1619 locations_changed ();
1621 if (_session_range_location) {
1622 AudioFileSource::set_header_position_offset (_session_range_location->start());
1625 if ((child = find_named_node (node, "Regions")) == 0) {
1626 error << _("Session: XML state has no Regions section") << endmsg;
1628 } else if (load_regions (*child)) {
1632 if ((child = find_named_node (node, "Playlists")) == 0) {
1633 error << _("Session: XML state has no playlists section") << endmsg;
1635 } else if (playlists->load (*this, *child)) {
1639 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1641 } else if (playlists->load_unused (*this, *child)) {
1645 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1646 if (load_compounds (*child)) {
1651 if (version >= 3000) {
1652 if ((child = find_named_node (node, "Bundles")) == 0) {
1653 warning << _("Session: XML state has no bundles section") << endmsg;
1656 /* We can't load Bundles yet as they need to be able
1657 * to convert from port names to Port objects, which can't happen until
1659 _bundle_xml_node = new XMLNode (*child);
1663 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1664 _vca_manager->set_state (*child, version);
1667 if ((child = find_named_node (node, "Routes")) == 0) {
1668 error << _("Session: XML state has no routes section") << endmsg;
1670 } else if (load_routes (*child, version)) {
1674 /* Now that we have Routes and masters loaded, connect them if appropriate */
1676 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1678 if (version >= 3000) {
1680 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1681 error << _("Session: XML state has no route groups section") << endmsg;
1683 } else if (load_route_groups (*child, version)) {
1687 } else if (version < 3000) {
1689 if ((child = find_named_node (node, "EditGroups")) == 0) {
1690 error << _("Session: XML state has no edit groups section") << endmsg;
1692 } else if (load_route_groups (*child, version)) {
1696 if ((child = find_named_node (node, "MixGroups")) == 0) {
1697 error << _("Session: XML state has no mix groups section") << endmsg;
1699 } else if (load_route_groups (*child, version)) {
1704 if ((child = find_named_node (node, "Click")) == 0) {
1705 warning << _("Session: XML state has no click section") << endmsg;
1706 } else if (_click_io) {
1707 setup_click_state (&node);
1710 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1711 ControlProtocolManager::instance().set_state (*child, version);
1714 if ((child = find_named_node (node, "Script"))) {
1715 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1716 if (!(*n)->is_content ()) { continue; }
1718 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1720 Glib::Threads::Mutex::Lock lm (lua_lock);
1721 (*_lua_load)(std::string ((const char*)buf, size));
1722 } catch (luabridge::LuaException const& e) {
1723 cerr << "LuaException:" << e.what () << endl;
1729 if ((child = find_named_node (node, X_("Selection")))) {
1730 _selection->set_state (*child, version);
1733 update_route_record_state ();
1735 /* here beginneth the second phase ... */
1736 set_snapshot_name (_current_snapshot_name);
1738 StateReady (); /* EMIT SIGNAL */
1751 Session::load_routes (const XMLNode& node, int version)
1754 XMLNodeConstIterator niter;
1755 RouteList new_routes;
1757 nlist = node.children();
1761 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1763 boost::shared_ptr<Route> route;
1765 if (version < 3000) {
1766 route = XMLRouteFactory_2X (**niter, version);
1767 } else if (version < 5000) {
1768 route = XMLRouteFactory_3X (**niter, version);
1770 route = XMLRouteFactory (**niter, version);
1774 error << _("Session: cannot create Route from XML description.") << endmsg;
1778 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1780 new_routes.push_back (route);
1783 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1785 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1787 BootMessage (_("Finished adding tracks/busses"));
1792 boost::shared_ptr<Route>
1793 Session::XMLRouteFactory (const XMLNode& node, int version)
1795 boost::shared_ptr<Route> ret;
1797 if (node.name() != "Route") {
1801 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1804 pl_prop = node.property (X_("midi-playlist"));
1807 DataType type = DataType::AUDIO;
1808 node.get_property("default-type", type);
1810 assert (type != DataType::NIL);
1814 /* has at least 1 playlist, therefore a track ... */
1816 boost::shared_ptr<Track> track;
1818 if (type == DataType::AUDIO) {
1819 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1821 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1824 if (track->init()) {
1828 if (track->set_state (node, version)) {
1832 BOOST_MARK_TRACK (track);
1836 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1837 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1840 if (r->init () == 0 && r->set_state (node, version) == 0) {
1841 BOOST_MARK_ROUTE (r);
1849 boost::shared_ptr<Route>
1850 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1852 boost::shared_ptr<Route> ret;
1854 if (node.name() != "Route") {
1858 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1860 DataType type = DataType::AUDIO;
1861 node.get_property("default-type", type);
1863 assert (type != DataType::NIL);
1867 boost::shared_ptr<Track> track;
1869 if (type == DataType::AUDIO) {
1870 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1872 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1875 if (track->init()) {
1879 if (track->set_state (node, version)) {
1883 BOOST_MARK_TRACK (track);
1887 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1888 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1890 if (r->init () == 0 && r->set_state (node, version) == 0) {
1891 BOOST_MARK_ROUTE (r);
1899 boost::shared_ptr<Route>
1900 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1902 boost::shared_ptr<Route> ret;
1904 if (node.name() != "Route") {
1908 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1910 ds_prop = node.property (X_("diskstream"));
1913 DataType type = DataType::AUDIO;
1914 node.get_property("default-type", type);
1916 assert (type != DataType::NIL);
1920 /* see comment in current ::set_state() regarding diskstream
1921 * state and DiskReader/DiskWRiter.
1924 error << _("Could not find diskstream for route") << endmsg;
1925 return boost::shared_ptr<Route> ();
1927 boost::shared_ptr<Track> track;
1929 if (type == DataType::AUDIO) {
1930 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1932 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1935 if (track->init()) {
1939 if (track->set_state (node, version)) {
1943 BOOST_MARK_TRACK (track);
1947 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1948 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1950 if (r->init () == 0 && r->set_state (node, version) == 0) {
1951 BOOST_MARK_ROUTE (r);
1960 Session::load_regions (const XMLNode& node)
1963 XMLNodeConstIterator niter;
1964 boost::shared_ptr<Region> region;
1966 nlist = node.children();
1970 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1971 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1972 error << _("Session: cannot create Region from XML description.");
1973 XMLProperty const * name = (**niter).property("name");
1976 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1987 Session::load_compounds (const XMLNode& node)
1989 XMLNodeList calist = node.children();
1990 XMLNodeConstIterator caiter;
1991 XMLProperty const * caprop;
1993 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1994 XMLNode* ca = *caiter;
1998 if ((caprop = ca->property (X_("original"))) == 0) {
2001 orig_id = caprop->value();
2003 if ((caprop = ca->property (X_("copy"))) == 0) {
2006 copy_id = caprop->value();
2008 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2009 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2011 if (!orig || !copy) {
2012 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2018 RegionFactory::add_compound_association (orig, copy);
2025 Session::load_nested_sources (const XMLNode& node)
2028 XMLNodeConstIterator niter;
2030 nlist = node.children();
2032 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2033 if ((*niter)->name() == "Source") {
2035 /* it may already exist, so don't recreate it unnecessarily
2038 XMLProperty const * prop = (*niter)->property (X_("id"));
2040 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2044 ID source_id (prop->value());
2046 if (!source_by_id (source_id)) {
2049 SourceFactory::create (*this, **niter, true);
2051 catch (failed_constructor& err) {
2052 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2059 boost::shared_ptr<Region>
2060 Session::XMLRegionFactory (const XMLNode& node, bool full)
2062 XMLProperty const * type = node.property("type");
2066 const XMLNodeList& nlist = node.children();
2068 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2069 XMLNode *child = (*niter);
2070 if (child->name() == "NestedSource") {
2071 load_nested_sources (*child);
2075 if (!type || type->value() == "audio") {
2076 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2077 } else if (type->value() == "midi") {
2078 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2081 } catch (failed_constructor& err) {
2082 return boost::shared_ptr<Region> ();
2085 return boost::shared_ptr<Region> ();
2088 boost::shared_ptr<AudioRegion>
2089 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2091 XMLProperty const * prop;
2092 boost::shared_ptr<Source> source;
2093 boost::shared_ptr<AudioSource> as;
2095 SourceList master_sources;
2096 uint32_t nchans = 1;
2099 if (node.name() != X_("Region")) {
2100 return boost::shared_ptr<AudioRegion>();
2103 node.get_property (X_("channels"), nchans);
2105 if ((prop = node.property ("name")) == 0) {
2106 cerr << "no name for this region\n";
2110 if ((prop = node.property (X_("source-0"))) == 0) {
2111 if ((prop = node.property ("source")) == 0) {
2112 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2113 return boost::shared_ptr<AudioRegion>();
2117 PBD::ID s_id (prop->value());
2119 if ((source = source_by_id (s_id)) == 0) {
2120 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2121 return boost::shared_ptr<AudioRegion>();
2124 as = boost::dynamic_pointer_cast<AudioSource>(source);
2126 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2127 return boost::shared_ptr<AudioRegion>();
2130 sources.push_back (as);
2132 /* pickup other channels */
2134 for (uint32_t n=1; n < nchans; ++n) {
2135 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2136 if ((prop = node.property (buf)) != 0) {
2138 PBD::ID id2 (prop->value());
2140 if ((source = source_by_id (id2)) == 0) {
2141 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2142 return boost::shared_ptr<AudioRegion>();
2145 as = boost::dynamic_pointer_cast<AudioSource>(source);
2147 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2148 return boost::shared_ptr<AudioRegion>();
2150 sources.push_back (as);
2154 for (uint32_t n = 0; n < nchans; ++n) {
2155 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2156 if ((prop = node.property (buf)) != 0) {
2158 PBD::ID id2 (prop->value());
2160 if ((source = source_by_id (id2)) == 0) {
2161 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2162 return boost::shared_ptr<AudioRegion>();
2165 as = boost::dynamic_pointer_cast<AudioSource>(source);
2167 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2168 return boost::shared_ptr<AudioRegion>();
2170 master_sources.push_back (as);
2175 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2177 /* a final detail: this is the one and only place that we know how long missing files are */
2179 if (region->whole_file()) {
2180 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2181 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2183 sfp->set_length (region->length());
2188 if (!master_sources.empty()) {
2189 if (master_sources.size() != nchans) {
2190 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2192 region->set_master_sources (master_sources);
2200 catch (failed_constructor& err) {
2201 return boost::shared_ptr<AudioRegion>();
2205 boost::shared_ptr<MidiRegion>
2206 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2208 XMLProperty const * prop;
2209 boost::shared_ptr<Source> source;
2210 boost::shared_ptr<MidiSource> ms;
2213 if (node.name() != X_("Region")) {
2214 return boost::shared_ptr<MidiRegion>();
2217 if ((prop = node.property ("name")) == 0) {
2218 cerr << "no name for this region\n";
2222 if ((prop = node.property (X_("source-0"))) == 0) {
2223 if ((prop = node.property ("source")) == 0) {
2224 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2225 return boost::shared_ptr<MidiRegion>();
2229 PBD::ID s_id (prop->value());
2231 if ((source = source_by_id (s_id)) == 0) {
2232 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2233 return boost::shared_ptr<MidiRegion>();
2236 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2238 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2239 return boost::shared_ptr<MidiRegion>();
2242 sources.push_back (ms);
2245 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2246 /* a final detail: this is the one and only place that we know how long missing files are */
2248 if (region->whole_file()) {
2249 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2250 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2252 sfp->set_length (region->length());
2260 catch (failed_constructor& err) {
2261 return boost::shared_ptr<MidiRegion>();
2266 Session::get_sources_as_xml ()
2269 XMLNode* node = new XMLNode (X_("Sources"));
2270 Glib::Threads::Mutex::Lock lm (source_lock);
2272 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2273 node->add_child_nocopy (i->second->get_state());
2280 Session::reset_write_sources (bool mark_write_complete, bool force)
2282 boost::shared_ptr<RouteList> rl = routes.reader();
2283 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2284 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2286 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2287 tr->reset_write_sources(mark_write_complete, force);
2288 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2294 Session::load_sources (const XMLNode& node)
2297 XMLNodeConstIterator niter;
2298 /* don't need this but it stops some
2299 * versions of gcc complaining about
2300 * discarded return values.
2302 boost::shared_ptr<Source> source;
2304 nlist = node.children();
2307 std::map<std::string, std::string> relocation;
2309 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2310 #ifdef PLATFORM_WINDOWS
2314 XMLNode srcnode (**niter);
2315 bool try_replace_abspath = true;
2319 #ifdef PLATFORM_WINDOWS
2320 // do not show "insert media" popups (files embedded from removable media).
2321 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2323 if ((source = XMLSourceFactory (srcnode)) == 0) {
2324 error << _("Session: cannot create Source from XML description.") << endmsg;
2326 #ifdef PLATFORM_WINDOWS
2327 SetErrorMode(old_mode);
2330 } catch (MissingSource& err) {
2331 #ifdef PLATFORM_WINDOWS
2332 SetErrorMode(old_mode);
2335 /* try previous abs path replacements first */
2336 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2337 std::string dir = Glib::path_get_dirname (err.path);
2338 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2339 if (rl != relocation.end ()) {
2340 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2341 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2342 srcnode.set_property ("origin", newpath);
2343 try_replace_abspath = false;
2350 _missing_file_replacement = "";
2352 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2353 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2354 PROGRAM_NAME) << endmsg;
2358 if (!no_questions_about_missing_files) {
2359 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2364 switch (user_choice) {
2366 /* user added a new search location
2367 * or selected a new absolute path,
2369 if (Glib::path_is_absolute (err.path)) {
2370 if (!_missing_file_replacement.empty ()) {
2371 /* replace origin, in XML */
2372 std::string newpath = Glib::build_filename (
2373 _missing_file_replacement, Glib::path_get_basename (err.path));
2374 srcnode.set_property ("origin", newpath);
2375 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2376 _missing_file_replacement = "";
2383 /* user asked to quit the entire session load */
2387 no_questions_about_missing_files = true;
2391 no_questions_about_missing_files = true;
2398 case DataType::AUDIO:
2399 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2402 case DataType::MIDI:
2403 /* The MIDI file is actually missing so
2404 * just create a new one in the same
2405 * location. Do not announce its
2409 if (!Glib::path_is_absolute (err.path)) {
2410 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2412 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2417 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2418 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2419 /* reset ID to match the missing one */
2420 source->set_id (**niter);
2421 /* Now we can announce it */
2422 SourceFactory::SourceCreated (source);
2433 boost::shared_ptr<Source>
2434 Session::XMLSourceFactory (const XMLNode& node)
2436 if (node.name() != "Source") {
2437 return boost::shared_ptr<Source>();
2441 /* note: do peak building in another thread when loading session state */
2442 return SourceFactory::create (*this, node, true);
2445 catch (failed_constructor& err) {
2446 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2447 return boost::shared_ptr<Source>();
2452 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2454 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2458 bool absolute_path = Glib::path_is_absolute (template_name);
2460 /* directory to put the template in */
2461 std::string template_dir_path;
2463 if (!absolute_path) {
2464 std::string user_template_dir(user_template_directory());
2466 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2467 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2468 user_template_dir, g_strerror (errno)) << endmsg;
2472 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2474 template_dir_path = template_name;
2477 if (!ARDOUR::Profile->get_trx()) {
2478 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2479 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2480 template_dir_path) << endmsg;
2484 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2485 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2486 template_dir_path, g_strerror (errno)) << endmsg;
2492 std::string template_file_path;
2494 if (ARDOUR::Profile->get_trx()) {
2495 template_file_path = template_name;
2497 if (absolute_path) {
2498 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2500 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2504 SessionSaveUnderway (); /* EMIT SIGNAL */
2509 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2510 root = &get_template ();
2513 root->remove_nodes_and_delete (X_("description"));
2515 if (!description.empty()) {
2516 XMLNode* desc = new XMLNode (X_("description"));
2517 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2518 desc->add_child_nocopy (*desc_cont);
2520 root->add_child_nocopy (*desc);
2523 tree.set_root (root);
2525 if (!tree.write (template_file_path)) {
2526 error << _("template not saved") << endmsg;
2530 store_recent_templates (template_file_path);
2536 Session::refresh_disk_space ()
2538 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2540 Glib::Threads::Mutex::Lock lm (space_lock);
2542 /* get freespace on every FS that is part of the session path */
2544 _total_free_4k_blocks = 0;
2545 _total_free_4k_blocks_uncertain = false;
2547 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2548 #if defined(__NetBSD__)
2549 struct statvfs statfsbuf;
2551 statvfs (i->path.c_str(), &statfsbuf);
2553 struct statfs statfsbuf;
2555 statfs (i->path.c_str(), &statfsbuf);
2557 double const scale = statfsbuf.f_bsize / 4096.0;
2559 /* See if this filesystem is read-only */
2560 struct statvfs statvfsbuf;
2561 statvfs (i->path.c_str(), &statvfsbuf);
2563 /* f_bavail can be 0 if it is undefined for whatever
2564 filesystem we are looking at; Samba shares mounted
2565 via GVFS are an example of this.
2567 if (statfsbuf.f_bavail == 0) {
2568 /* block count unknown */
2570 i->blocks_unknown = true;
2571 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2572 /* read-only filesystem */
2574 i->blocks_unknown = false;
2576 /* read/write filesystem with known space */
2577 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2578 i->blocks_unknown = false;
2581 _total_free_4k_blocks += i->blocks;
2582 if (i->blocks_unknown) {
2583 _total_free_4k_blocks_uncertain = true;
2586 #elif defined PLATFORM_WINDOWS
2587 vector<string> scanned_volumes;
2588 vector<string>::iterator j;
2589 vector<space_and_path>::iterator i;
2590 DWORD nSectorsPerCluster, nBytesPerSector,
2591 nFreeClusters, nTotalClusters;
2595 _total_free_4k_blocks = 0;
2597 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2598 strncpy (disk_drive, (*i).path.c_str(), 3);
2602 volume_found = false;
2603 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2605 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2606 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2607 i->blocks = (uint32_t)(nFreeBytes / 4096);
2609 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2610 if (0 == j->compare(disk_drive)) {
2611 volume_found = true;
2616 if (!volume_found) {
2617 scanned_volumes.push_back(disk_drive);
2618 _total_free_4k_blocks += i->blocks;
2623 if (0 == _total_free_4k_blocks) {
2624 strncpy (disk_drive, path().c_str(), 3);
2627 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2629 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2630 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2631 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2638 Session::get_best_session_directory_for_new_audio ()
2640 vector<space_and_path>::iterator i;
2641 string result = _session_dir->root_path();
2643 /* handle common case without system calls */
2645 if (session_dirs.size() == 1) {
2649 /* OK, here's the algorithm we're following here:
2651 We want to select which directory to use for
2652 the next file source to be created. Ideally,
2653 we'd like to use a round-robin process so as to
2654 get maximum performance benefits from splitting
2655 the files across multiple disks.
2657 However, in situations without much diskspace, an
2658 RR approach may end up filling up a filesystem
2659 with new files while others still have space.
2660 Its therefore important to pay some attention to
2661 the freespace in the filesystem holding each
2662 directory as well. However, if we did that by
2663 itself, we'd keep creating new files in the file
2664 system with the most space until it was as full
2665 as all others, thus negating any performance
2666 benefits of this RAID-1 like approach.
2668 So, we use a user-configurable space threshold. If
2669 there are at least 2 filesystems with more than this
2670 much space available, we use RR selection between them.
2671 If not, then we pick the filesystem with the most space.
2673 This gets a good balance between the two
2677 refresh_disk_space ();
2679 int free_enough = 0;
2681 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2682 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2687 if (free_enough >= 2) {
2688 /* use RR selection process, ensuring that the one
2692 i = last_rr_session_dir;
2695 if (++i == session_dirs.end()) {
2696 i = session_dirs.begin();
2699 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2700 SessionDirectory sdir(i->path);
2701 if (sdir.create ()) {
2703 last_rr_session_dir = i;
2708 } while (i != last_rr_session_dir);
2712 /* pick FS with the most freespace (and that
2713 seems to actually work ...)
2716 vector<space_and_path> sorted;
2717 space_and_path_ascending_cmp cmp;
2719 sorted = session_dirs;
2720 sort (sorted.begin(), sorted.end(), cmp);
2722 for (i = sorted.begin(); i != sorted.end(); ++i) {
2723 SessionDirectory sdir(i->path);
2724 if (sdir.create ()) {
2726 last_rr_session_dir = i;
2736 Session::automation_dir () const
2738 return Glib::build_filename (_path, automation_dir_name);
2742 Session::analysis_dir () const
2744 return Glib::build_filename (_path, analysis_dir_name);
2748 Session::plugins_dir () const
2750 return Glib::build_filename (_path, plugins_dir_name);
2754 Session::externals_dir () const
2756 return Glib::build_filename (_path, externals_dir_name);
2760 Session::load_bundles (XMLNode const & node)
2762 XMLNodeList nlist = node.children();
2763 XMLNodeConstIterator niter;
2767 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2768 if ((*niter)->name() == "InputBundle") {
2769 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2770 } else if ((*niter)->name() == "OutputBundle") {
2771 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2773 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2782 Session::load_route_groups (const XMLNode& node, int version)
2784 XMLNodeList nlist = node.children();
2785 XMLNodeConstIterator niter;
2789 if (version >= 3000) {
2791 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2792 if ((*niter)->name() == "RouteGroup") {
2793 RouteGroup* rg = new RouteGroup (*this, "");
2794 add_route_group (rg);
2795 rg->set_state (**niter, version);
2799 } else if (version < 3000) {
2801 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2802 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2803 RouteGroup* rg = new RouteGroup (*this, "");
2804 add_route_group (rg);
2805 rg->set_state (**niter, version);
2814 state_file_filter (const string &str, void* /*arg*/)
2816 return (str.length() > strlen(statefile_suffix) &&
2817 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2821 remove_end(string state)
2823 string statename(state);
2825 string::size_type start,end;
2826 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2827 statename = statename.substr (start+1);
2830 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2831 end = statename.length();
2834 return string(statename.substr (0, end));
2838 Session::possible_states (string path)
2840 vector<string> states;
2841 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2843 transform(states.begin(), states.end(), states.begin(), remove_end);
2845 sort (states.begin(), states.end());
2851 Session::possible_states () const
2853 return possible_states(_path);
2857 Session::new_route_group (const std::string& name)
2859 RouteGroup* rg = NULL;
2861 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2862 if ((*i)->name () == name) {
2869 rg = new RouteGroup (*this, name);
2870 add_route_group (rg);
2876 Session::add_route_group (RouteGroup* g)
2878 _route_groups.push_back (g);
2879 route_group_added (g); /* EMIT SIGNAL */
2881 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2882 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2883 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2889 Session::remove_route_group (RouteGroup& rg)
2891 list<RouteGroup*>::iterator i;
2893 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2894 _route_groups.erase (i);
2897 route_group_removed (); /* EMIT SIGNAL */
2901 /** Set a new order for our route groups, without adding or removing any.
2902 * @param groups Route group list in the new order.
2905 Session::reorder_route_groups (list<RouteGroup*> groups)
2907 _route_groups = groups;
2909 route_groups_reordered (); /* EMIT SIGNAL */
2915 Session::route_group_by_name (string name)
2917 list<RouteGroup *>::iterator i;
2919 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2920 if ((*i)->name() == name) {
2928 Session::all_route_group() const
2930 return *_all_route_group;
2934 Session::add_commands (vector<Command*> const & cmds)
2936 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2942 Session::add_command (Command* const cmd)
2944 assert (_current_trans);
2945 DEBUG_UNDO_HISTORY (
2946 string_compose ("Current Undo Transaction %1, adding command: %2",
2947 _current_trans->name (),
2949 _current_trans->add_command (cmd);
2952 PBD::StatefulDiffCommand*
2953 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2955 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2961 Session::begin_reversible_command (const string& name)
2963 begin_reversible_command (g_quark_from_string (name.c_str ()));
2966 /** Begin a reversible command using a GQuark to identify it.
2967 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2968 * but there must be as many begin...()s as there are commit...()s.
2971 Session::begin_reversible_command (GQuark q)
2973 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2974 to hold all the commands that are committed. This keeps the order of
2975 commands correct in the history.
2978 if (_current_trans == 0) {
2979 DEBUG_UNDO_HISTORY (string_compose (
2980 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2982 /* start a new transaction */
2983 assert (_current_trans_quarks.empty ());
2984 _current_trans = new UndoTransaction();
2985 _current_trans->set_name (g_quark_to_string (q));
2987 DEBUG_UNDO_HISTORY (
2988 string_compose ("Begin Reversible Command, current transaction: %1",
2989 _current_trans->name ()));
2992 _current_trans_quarks.push_front (q);
2996 Session::abort_reversible_command ()
2998 if (_current_trans != 0) {
2999 DEBUG_UNDO_HISTORY (
3000 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
3001 _current_trans->clear();
3002 delete _current_trans;
3004 _current_trans_quarks.clear();
3009 Session::commit_reversible_command (Command *cmd)
3011 assert (_current_trans);
3012 assert (!_current_trans_quarks.empty ());
3017 DEBUG_UNDO_HISTORY (
3018 string_compose ("Current Undo Transaction %1, adding command: %2",
3019 _current_trans->name (),
3021 _current_trans->add_command (cmd);
3024 DEBUG_UNDO_HISTORY (
3025 string_compose ("Commit Reversible Command, current transaction: %1",
3026 _current_trans->name ()));
3028 _current_trans_quarks.pop_front ();
3030 if (!_current_trans_quarks.empty ()) {
3031 DEBUG_UNDO_HISTORY (
3032 string_compose ("Commit Reversible Command, transaction is not "
3033 "top-level, current transaction: %1",
3034 _current_trans->name ()));
3035 /* the transaction we're committing is not the top-level one */
3039 if (_current_trans->empty()) {
3040 /* no commands were added to the transaction, so just get rid of it */
3041 DEBUG_UNDO_HISTORY (
3042 string_compose ("Commit Reversible Command, No commands were "
3043 "added to current transaction: %1",
3044 _current_trans->name ()));
3045 delete _current_trans;
3050 gettimeofday (&now, 0);
3051 _current_trans->set_timestamp (now);
3053 _history.add (_current_trans);
3058 accept_all_audio_files (const string& path, void* /*arg*/)
3060 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3064 if (!AudioFileSource::safe_audio_file_extension (path)) {
3072 accept_all_midi_files (const string& path, void* /*arg*/)
3074 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3078 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3079 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3080 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3084 accept_all_state_files (const string& path, void* /*arg*/)
3086 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3090 std::string const statefile_ext (statefile_suffix);
3091 if (path.length() >= statefile_ext.length()) {
3092 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3099 Session::find_all_sources (string path, set<string>& result)
3104 if (!tree.read (path)) {
3108 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3113 XMLNodeConstIterator niter;
3115 nlist = node->children();
3119 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3121 XMLProperty const * prop;
3123 if ((prop = (*niter)->property (X_("type"))) == 0) {
3127 DataType type (prop->value());
3129 if ((prop = (*niter)->property (X_("name"))) == 0) {
3133 if (Glib::path_is_absolute (prop->value())) {
3134 /* external file, ignore */
3142 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3143 result.insert (found_path);
3151 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3153 vector<string> state_files;
3155 string this_snapshot_path;
3161 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3162 ripped = ripped.substr (0, ripped.length() - 1);
3165 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3167 if (state_files.empty()) {
3172 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3173 this_snapshot_path += statefile_suffix;
3175 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3177 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3179 if (exclude_this_snapshot && *i == this_snapshot_path) {
3180 cerr << "\texcluded\n";
3185 if (find_all_sources (*i, result) < 0) {
3193 struct RegionCounter {
3194 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3195 AudioSourceList::iterator iter;
3196 boost::shared_ptr<Region> region;
3199 RegionCounter() : count (0) {}
3203 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3205 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3206 return r.get_value_or (1);
3210 Session::cleanup_regions ()
3212 bool removed = false;
3213 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3215 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3217 uint32_t used = playlists->region_use_count (i->second);
3219 if (used == 0 && !i->second->automatic ()) {
3220 boost::weak_ptr<Region> w = i->second;
3223 RegionFactory::map_remove (w);
3230 // re-check to remove parent references of compound regions
3231 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3232 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3236 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3237 if (0 == playlists->region_use_count (i->second)) {
3238 boost::weak_ptr<Region> w = i->second;
3240 RegionFactory::map_remove (w);
3247 /* dump the history list */
3254 Session::can_cleanup_peakfiles () const
3256 if (deletion_in_progress()) {
3259 if (!_writable || (_state_of_the_state & CannotSave)) {
3260 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3263 if (record_status() == Recording) {
3264 error << _("Cannot cleanup peak-files while recording") << endmsg;
3271 Session::cleanup_peakfiles ()
3273 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3278 assert (can_cleanup_peakfiles ());
3279 assert (!peaks_cleanup_in_progres());
3281 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3283 int timeout = 5000; // 5 seconds
3284 while (!SourceFactory::files_with_peaks.empty()) {
3285 Glib::usleep (1000);
3286 if (--timeout < 0) {
3287 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3288 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3293 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3294 boost::shared_ptr<AudioSource> as;
3295 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3296 as->close_peakfile();
3300 PBD::clear_directory (session_directory().peak_path());
3302 _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 SourceFactory::setup_peakfile(as, true);
3314 Session::cleanup_sources (CleanupReport& rep)
3316 // FIXME: needs adaptation to midi
3318 vector<boost::shared_ptr<Source> > dead_sources;
3321 vector<string> candidates;
3322 vector<string> unused;
3323 set<string> sources_used_by_all_snapshots;
3330 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3332 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3334 /* this is mostly for windows which doesn't allow file
3335 * renaming if the file is in use. But we don't special
3336 * case it because we need to know if this causes
3337 * problems, and the easiest way to notice that is to
3338 * keep it in place for all platforms.
3341 request_stop (false);
3343 _butler->wait_until_finished ();
3345 /* consider deleting all unused playlists */
3347 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3352 /* sync the "all regions" property of each playlist with its current state */
3354 playlists->sync_all_regions_with_regions ();
3356 /* find all un-used sources */
3361 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3363 SourceMap::iterator tmp;
3368 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3372 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3373 dead_sources.push_back (i->second);
3374 i->second->drop_references ();
3380 /* build a list of all the possible audio directories for the session */
3382 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3383 SessionDirectory sdir ((*i).path);
3384 asp += sdir.sound_path();
3386 audio_path += asp.to_string();
3389 /* build a list of all the possible midi directories for the session */
3391 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3392 SessionDirectory sdir ((*i).path);
3393 msp += sdir.midi_path();
3395 midi_path += msp.to_string();
3397 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3398 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3400 /* add sources from all other snapshots as "used", but don't use this
3401 snapshot because the state file on disk still references sources we
3402 may have already dropped.
3405 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3407 /* Although the region factory has a list of all regions ever created
3408 * for this session, we're only interested in regions actually in
3409 * playlists right now. So merge all playlist regions lists together.
3411 * This will include the playlists used within compound regions.
3414 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3416 /* add our current source list
3419 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3420 boost::shared_ptr<FileSource> fs;
3421 SourceMap::iterator tmp = i;
3424 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3430 /* this is mostly for windows which doesn't allow file
3431 * renaming if the file is in use. But we do not special
3432 * case it because we need to know if this causes
3433 * problems, and the easiest way to notice that is to
3434 * keep it in place for all platforms.
3439 if (!fs->is_stub()) {
3441 /* Note that we're checking a list of all
3442 * sources across all snapshots with the list
3443 * of sources used by this snapshot.
3446 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3447 /* this source is in use by this snapshot */
3448 sources_used_by_all_snapshots.insert (fs->path());
3449 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3451 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3452 /* this source is NOT in use by this snapshot */
3454 /* remove all related regions from RegionFactory master list */
3456 RegionFactory::remove_regions_using_source (i->second);
3458 /* remove from our current source list
3459 * also. We may not remove it from
3460 * disk, because it may be used by
3461 * other snapshots, but it isn't used inside this
3462 * snapshot anymore, so we don't need a
3473 /* now check each candidate source to see if it exists in the list of
3474 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3477 cerr << "Candidates: " << candidates.size() << endl;
3478 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3480 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3485 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3487 tmppath1 = canonical_path (spath);
3488 tmppath2 = canonical_path ((*i));
3490 cerr << "\t => " << tmppath2 << endl;
3492 if (tmppath1 == tmppath2) {
3499 unused.push_back (spath);
3503 cerr << "Actually unused: " << unused.size() << endl;
3505 if (unused.empty()) {
3511 /* now try to move all unused files into the "dead" directory(ies) */
3513 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3518 /* don't move the file across filesystems, just
3519 * stick it in the `dead_dir_name' directory
3520 * on whichever filesystem it was already on.
3523 if ((*x).find ("/sounds/") != string::npos) {
3525 /* old school, go up 1 level */
3527 newpath = Glib::path_get_dirname (*x); // "sounds"
3528 newpath = Glib::path_get_dirname (newpath); // "session-name"
3532 /* new school, go up 4 levels */
3534 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3535 newpath = Glib::path_get_dirname (newpath); // "session-name"
3536 newpath = Glib::path_get_dirname (newpath); // "interchange"
3537 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3540 newpath = Glib::build_filename (newpath, dead_dir_name);
3542 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3543 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3547 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3549 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3551 /* the new path already exists, try versioning */
3553 char buf[PATH_MAX+1];
3557 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3560 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3561 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3565 if (version == 999) {
3566 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3570 newpath = newpath_v;
3575 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3576 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3577 newpath, g_strerror (errno)) << endmsg;
3581 /* see if there an easy to find peakfile for this file, and remove it. */
3583 string base = Glib::path_get_basename (*x);
3584 base += "%A"; /* this is what we add for the channel suffix of all native files,
3585 * or for the first channel of embedded files. it will miss
3586 * some peakfiles for other channels
3588 string peakpath = construct_peak_filepath (base);
3590 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3591 if (::g_unlink (peakpath.c_str ()) != 0) {
3592 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3593 g_strerror (errno)) << endmsg;
3594 /* try to back out */
3595 ::g_rename (newpath.c_str (), _path.c_str ());
3600 rep.paths.push_back (*x);
3601 rep.space += statbuf.st_size;
3604 /* dump the history list */
3608 /* save state so we don't end up a session file
3609 * referring to non-existent sources.
3616 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3622 Session::cleanup_trash_sources (CleanupReport& rep)
3624 // FIXME: needs adaptation for MIDI
3626 vector<space_and_path>::iterator i;
3632 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3634 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3636 clear_directory (dead_dir, &rep.space, &rep.paths);
3643 Session::set_dirty ()
3645 /* return early if there's nothing to do */
3650 /* never mark session dirty during loading */
3651 if (_state_of_the_state & Loading) {
3655 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3656 DirtyChanged(); /* EMIT SIGNAL */
3660 Session::set_clean ()
3662 bool was_dirty = dirty();
3664 _state_of_the_state = Clean;
3667 DirtyChanged(); /* EMIT SIGNAL */
3672 Session::set_deletion_in_progress ()
3674 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3678 Session::clear_deletion_in_progress ()
3680 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3684 Session::add_controllable (boost::shared_ptr<Controllable> c)
3686 /* this adds a controllable to the list managed by the Session.
3687 this is a subset of those managed by the Controllable class
3688 itself, and represents the only ones whose state will be saved
3689 as part of the session.
3692 Glib::Threads::Mutex::Lock lm (controllables_lock);
3693 controllables.insert (c);
3696 struct null_deleter { void operator()(void const *) const {} };
3699 Session::remove_controllable (Controllable* c)
3701 if (_state_of_the_state & Deletion) {
3705 Glib::Threads::Mutex::Lock lm (controllables_lock);
3707 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3709 if (x != controllables.end()) {
3710 controllables.erase (x);
3714 boost::shared_ptr<Controllable>
3715 Session::controllable_by_id (const PBD::ID& id)
3717 Glib::Threads::Mutex::Lock lm (controllables_lock);
3719 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3720 if ((*i)->id() == id) {
3725 return boost::shared_ptr<Controllable>();
3728 boost::shared_ptr<AutomationControl>
3729 Session::automation_control_by_id (const PBD::ID& id)
3731 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3734 boost::shared_ptr<Controllable>
3735 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3737 boost::shared_ptr<Controllable> c;
3738 boost::shared_ptr<Stripable> s;
3739 boost::shared_ptr<Route> r;
3741 switch (desc.top_level_type()) {
3742 case ControllableDescriptor::NamedRoute:
3744 std::string str = desc.top_level_name();
3746 if (str == "Master" || str == "master") {
3748 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3750 } else if (str == "auditioner") {
3753 s = route_by_name (desc.top_level_name());
3759 case ControllableDescriptor::PresentationOrderRoute:
3760 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3763 case ControllableDescriptor::PresentationOrderTrack:
3764 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3767 case ControllableDescriptor::PresentationOrderBus:
3768 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3771 case ControllableDescriptor::PresentationOrderVCA:
3772 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3775 case ControllableDescriptor::SelectionCount:
3776 s = route_by_selected_count (desc.selection_id());
3784 r = boost::dynamic_pointer_cast<Route> (s);
3786 switch (desc.subtype()) {
3787 case GainAutomation:
3788 c = s->gain_control ();
3791 case TrimAutomation:
3792 c = s->trim_control ();
3795 case SoloAutomation:
3796 c = s->solo_control();
3799 case MuteAutomation:
3800 c = s->mute_control();
3803 case RecEnableAutomation:
3804 c = s->rec_enable_control ();
3807 case PanAzimuthAutomation:
3808 c = s->pan_azimuth_control();
3811 case PanWidthAutomation:
3812 c = s->pan_width_control();
3815 case PanElevationAutomation:
3816 c = s->pan_elevation_control();
3819 case PluginAutomation:
3821 uint32_t plugin = desc.target (0);
3822 uint32_t parameter_index = desc.target (1);
3824 /* revert to zero based counting */
3830 if (parameter_index > 0) {
3838 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3841 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3842 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3847 case SendLevelAutomation: {
3848 uint32_t send = desc.target (0);
3855 c = r->send_level_controllable (send);
3860 /* relax and return a null pointer */
3868 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3871 Stateful::add_instant_xml (node, _path);
3874 if (write_to_config) {
3875 Config->add_instant_xml (node);
3880 Session::instant_xml (const string& node_name)
3882 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3883 if (get_disable_all_loaded_plugins ()) {
3887 return Stateful::instant_xml (node_name, _path);
3891 Session::save_history (string snapshot_name)
3899 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3900 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3904 if (snapshot_name.empty()) {
3905 snapshot_name = _current_snapshot_name;
3908 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3909 const string backup_filename = history_filename + backup_suffix;
3910 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3911 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3913 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3914 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3915 error << _("could not backup old history file, current history not saved") << endmsg;
3920 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3922 if (!tree.write (xml_path))
3924 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3926 if (g_remove (xml_path.c_str()) != 0) {
3927 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3928 xml_path, g_strerror (errno)) << endmsg;
3930 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3931 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3932 backup_path, g_strerror (errno)) << endmsg;
3942 Session::restore_history (string snapshot_name)
3946 if (snapshot_name.empty()) {
3947 snapshot_name = _current_snapshot_name;
3950 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3951 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3953 info << "Loading history from " << xml_path << endmsg;
3955 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3956 info << string_compose (_("%1: no history file \"%2\" for this session."),
3957 _name, xml_path) << endmsg;
3961 if (!tree.read (xml_path)) {
3962 error << string_compose (_("Could not understand session history file \"%1\""),
3963 xml_path) << endmsg;
3970 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3978 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3979 !t->get_property ("tv-usec", tv_usec)) {
3983 UndoTransaction* ut = new UndoTransaction ();
3984 ut->set_name (name);
3988 tv.tv_usec = tv_usec;
3989 ut->set_timestamp(tv);
3991 for (XMLNodeConstIterator child_it = t->children().begin();
3992 child_it != t->children().end(); child_it++)
3994 XMLNode *n = *child_it;
3997 if (n->name() == "MementoCommand" ||
3998 n->name() == "MementoUndoCommand" ||
3999 n->name() == "MementoRedoCommand") {
4001 if ((c = memento_command_factory(n))) {
4005 } else if (n->name() == "NoteDiffCommand") {
4006 PBD::ID id (n->property("midi-source")->value());
4007 boost::shared_ptr<MidiSource> midi_source =
4008 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
4010 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
4012 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
4015 } else if (n->name() == "SysExDiffCommand") {
4017 PBD::ID id (n->property("midi-source")->value());
4018 boost::shared_ptr<MidiSource> midi_source =
4019 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
4021 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
4023 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
4026 } else if (n->name() == "PatchChangeDiffCommand") {
4028 PBD::ID id (n->property("midi-source")->value());
4029 boost::shared_ptr<MidiSource> midi_source =
4030 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
4032 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
4034 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
4037 } else if (n->name() == "StatefulDiffCommand") {
4038 if ((c = stateful_diff_command_factory (n))) {
4039 ut->add_command (c);
4042 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
4053 Session::config_changed (std::string p, bool ours)
4059 if (p == "auto-loop") {
4061 } else if (p == "session-monitoring") {
4063 } else if (p == "auto-input") {
4065 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4066 /* auto-input only makes a difference if we're rolling */
4067 set_track_monitor_input_status (!config.get_auto_input());
4070 } else if (p == "punch-in") {
4074 if ((location = _locations->auto_punch_location()) != 0) {
4076 if (config.get_punch_in ()) {
4077 auto_punch_start_changed (location);
4079 clear_events (SessionEvent::PunchIn);
4083 } else if (p == "punch-out") {
4087 if ((location = _locations->auto_punch_location()) != 0) {
4089 if (config.get_punch_out()) {
4090 auto_punch_end_changed (location);
4092 clear_events (SessionEvent::PunchOut);
4096 } else if (p == "edit-mode") {
4098 Glib::Threads::Mutex::Lock lm (playlists->lock);
4100 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4101 (*i)->set_edit_mode (Config->get_edit_mode ());
4104 } else if (p == "use-video-sync") {
4106 waiting_for_sync_offset = config.get_use_video_sync();
4108 } else if (p == "mmc-control") {
4110 //poke_midi_thread ();
4112 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4114 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4116 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4118 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4120 } else if (p == "midi-control") {
4122 //poke_midi_thread ();
4124 } else if (p == "raid-path") {
4126 setup_raid_path (config.get_raid_path());
4128 } else if (p == "timecode-format") {
4132 } else if (p == "video-pullup") {
4136 } else if (p == "seamless-loop") {
4138 if (play_loop && transport_rolling()) {
4139 // to reset diskstreams etc
4140 request_play_loop (true);
4143 } else if (p == "rf-speed") {
4145 cumulative_rf_motion = 0;
4148 } else if (p == "click-sound") {
4150 setup_click_sounds (1);
4152 } else if (p == "click-emphasis-sound") {
4154 setup_click_sounds (-1);
4156 } else if (p == "clicking") {
4158 if (Config->get_clicking()) {
4159 if (_click_io && click_data) { // don't require emphasis data
4166 } else if (p == "click-record-only") {
4168 _click_rec_only = Config->get_click_record_only();
4170 } else if (p == "click-gain") {
4173 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4176 } else if (p == "send-mtc") {
4178 if (Config->get_send_mtc ()) {
4179 /* mark us ready to send */
4180 next_quarter_frame_to_send = 0;
4183 } else if (p == "send-mmc") {
4185 _mmc->enable_send (Config->get_send_mmc ());
4186 if (Config->get_send_mmc ()) {
4187 /* re-initialize MMC */
4188 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4189 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4192 } else if (p == "jack-time-master") {
4194 engine().reset_timebase ();
4196 } else if (p == "native-file-header-format") {
4198 if (!first_file_header_format_reset) {
4199 reset_native_file_format ();
4202 first_file_header_format_reset = false;
4204 } else if (p == "native-file-data-format") {
4206 if (!first_file_data_format_reset) {
4207 reset_native_file_format ();
4210 first_file_data_format_reset = false;
4212 } else if (p == "external-sync") {
4213 if (!config.get_external_sync()) {
4214 drop_sync_source ();
4216 switch_to_sync_source (Config->get_sync_source());
4218 } else if (p == "denormal-model") {
4220 } else if (p == "history-depth") {
4221 set_history_depth (Config->get_history_depth());
4222 } else if (p == "remote-model") {
4223 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4226 } else if (p == "initial-program-change") {
4228 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4231 buf[0] = MIDI::program; // channel zero by default
4232 buf[1] = (Config->get_initial_program_change() & 0x7f);
4234 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4236 } else if (p == "solo-mute-override") {
4237 // catch_up_on_solo_mute_override ();
4238 } else if (p == "listen-position" || p == "pfl-position") {
4239 listen_position_changed ();
4240 } else if (p == "solo-control-is-listen-control") {
4241 solo_control_mode_changed ();
4242 } else if (p == "solo-mute-gain") {
4243 _solo_cut_control->Changed (true, Controllable::NoGroup);
4244 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4245 last_timecode_valid = false;
4246 } else if (p == "playback-buffer-seconds") {
4247 AudioSource::allocate_working_buffers (sample_rate());
4248 } else if (p == "ltc-source-port") {
4249 reconnect_ltc_input ();
4250 } else if (p == "ltc-sink-port") {
4251 reconnect_ltc_output ();
4252 } else if (p == "timecode-generator-offset") {
4253 ltc_tx_parse_offset();
4254 } else if (p == "auto-return-target-list") {
4255 follow_playhead_priority ();
4262 Session::set_history_depth (uint32_t d)
4264 _history.set_depth (d);
4267 /** Connect things to the MMC object */
4269 Session::setup_midi_machine_control ()
4271 _mmc = new MIDI::MachineControl;
4273 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4274 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4276 if (!async_out || !async_out) {
4280 /* XXXX argh, passing raw pointers back into libmidi++ */
4282 MIDI::Port* mmc_in = async_in.get();
4283 MIDI::Port* mmc_out = async_out.get();
4285 _mmc->set_ports (mmc_in, mmc_out);
4287 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4288 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4289 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4290 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4291 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4292 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4293 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4294 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4295 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4296 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4297 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4298 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4299 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4301 /* also handle MIDI SPP because its so common */
4303 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4304 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4305 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4308 boost::shared_ptr<Controllable>
4309 Session::solo_cut_control() const
4311 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4312 * controls in Ardour that currently get presented to the user in the GUI that require
4313 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4315 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4316 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4319 return _solo_cut_control;
4323 Session::save_snapshot_name (const std::string & n)
4325 /* assure Stateful::_instant_xml is loaded
4326 * add_instant_xml() only adds to existing data and defaults
4327 * to use an empty Tree otherwise
4329 instant_xml ("LastUsedSnapshot");
4331 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4332 last_used_snapshot->set_property ("name", n);
4333 add_instant_xml (*last_used_snapshot, false);
4337 Session::set_snapshot_name (const std::string & n)
4339 _current_snapshot_name = n;
4340 save_snapshot_name (n);
4344 Session::rename (const std::string& new_name)
4346 string legal_name = legalize_for_path (new_name);
4352 string const old_sources_root = _session_dir->sources_root();
4354 if (!_writable || (_state_of_the_state & CannotSave)) {
4355 error << _("Cannot rename read-only session.") << endmsg;
4356 return 0; // don't show "messed up" warning
4358 if (record_status() == Recording) {
4359 error << _("Cannot rename session while recording") << endmsg;
4360 return 0; // don't show "messed up" warning
4363 StateProtector stp (this);
4368 * interchange subdirectory
4372 * Backup files are left unchanged and not renamed.
4375 /* Windows requires that we close all files before attempting the
4376 * rename. This works on other platforms, but isn't necessary there.
4377 * Leave it in place for all platforms though, since it may help
4378 * catch issues that could arise if the way Source files work ever
4379 * change (since most developers are not using Windows).
4382 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4383 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4389 /* pass one: not 100% safe check that the new directory names don't
4393 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4397 /* this is a stupid hack because Glib::path_get_dirname() is
4398 * lexical-only, and so passing it /a/b/c/ gives a different
4399 * result than passing it /a/b/c ...
4402 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4403 oldstr = oldstr.substr (0, oldstr.length() - 1);
4406 string base = Glib::path_get_dirname (oldstr);
4408 newstr = Glib::build_filename (base, legal_name);
4410 cerr << "Looking for " << newstr << endl;
4412 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4413 cerr << " exists\n";
4422 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4428 /* this is a stupid hack because Glib::path_get_dirname() is
4429 * lexical-only, and so passing it /a/b/c/ gives a different
4430 * result than passing it /a/b/c ...
4433 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4434 oldstr = oldstr.substr (0, oldstr.length() - 1);
4437 string base = Glib::path_get_dirname (oldstr);
4438 newstr = Glib::build_filename (base, legal_name);
4440 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4442 cerr << "Rename " << oldstr << " => " << newstr << endl;
4443 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4444 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4445 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4449 /* Reset path in "session dirs" */
4454 /* reset primary SessionDirectory object */
4457 (*_session_dir) = newstr;
4462 /* now rename directory below session_dir/interchange */
4464 string old_interchange_dir;
4465 string new_interchange_dir;
4467 /* use newstr here because we renamed the path
4468 * (folder/directory) that used to be oldstr to newstr above
4471 v.push_back (newstr);
4472 v.push_back (interchange_dir_name);
4473 v.push_back (Glib::path_get_basename (oldstr));
4475 old_interchange_dir = Glib::build_filename (v);
4478 v.push_back (newstr);
4479 v.push_back (interchange_dir_name);
4480 v.push_back (legal_name);
4482 new_interchange_dir = Glib::build_filename (v);
4484 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4486 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4487 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4488 old_interchange_dir, new_interchange_dir,
4491 error << string_compose (_("renaming %s as %2 failed (%3)"),
4492 old_interchange_dir, new_interchange_dir,
4501 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4502 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4504 cerr << "Rename " << oldstr << " => " << newstr << endl;
4506 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4507 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4508 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4514 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4516 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4517 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4519 cerr << "Rename " << oldstr << " => " << newstr << endl;
4521 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4522 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4523 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4528 /* remove old name from recent sessions */
4529 remove_recent_sessions (_path);
4532 /* update file source paths */
4534 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4535 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4537 string p = fs->path ();
4538 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4540 SourceFactory::setup_peakfile(i->second, true);
4544 set_snapshot_name (new_name);
4549 /* save state again to get everything just right */
4551 save_state (_current_snapshot_name);
4553 /* add to recent sessions */
4555 store_recent_sessions (new_name, _path);
4561 Session::parse_stateful_loading_version (const std::string& version)
4563 if (version.empty ()) {
4564 /* no version implies very old version of Ardour */
4568 if (version.find ('.') != string::npos) {
4569 /* old school version format */
4570 if (version[0] == '2') {
4576 return string_to<int32_t>(version);
4581 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4583 bool found_sr = false;
4584 bool found_data_format = false;
4585 std::string version;
4586 program_version = "";
4588 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4592 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4596 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4599 xmlFreeParserCtxt(ctxt);
4603 xmlNodePtr node = xmlDocGetRootElement(doc);
4606 xmlFreeParserCtxt(ctxt);
4611 /* sample rate & version*/
4614 for (attr = node->properties; attr; attr = attr->next) {
4615 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4616 version = std::string ((char*)attr->children->content);
4618 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4619 sample_rate = atoi ((char*)attr->children->content);
4624 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4628 node = node->children;
4629 while (node != NULL) {
4630 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4631 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4633 program_version = string ((const char*)val);
4634 size_t sep = program_version.find_first_of("-");
4635 if (sep != string::npos) {
4636 program_version = program_version.substr (0, sep);
4641 if (strcmp((const char*) node->name, "Config")) {
4645 for (node = node->children; node; node = node->next) {
4646 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4647 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4649 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4652 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4654 found_data_format = true;
4655 } catch (PBD::unknown_enumeration& e) {}
4665 xmlFreeParserCtxt(ctxt);
4668 return (found_sr && found_data_format) ? 0 : 1;
4672 Session::get_snapshot_from_instant (const std::string& session_dir)
4674 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4676 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4681 if (!tree.read (instant_xml_path)) {
4685 XMLProperty const * prop;
4686 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4687 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4688 return prop->value();
4694 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4695 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4698 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4702 SourcePathMap source_path_map;
4704 boost::shared_ptr<AudioFileSource> afs;
4709 Glib::Threads::Mutex::Lock lm (source_lock);
4711 cerr << " total sources = " << sources.size();
4713 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4714 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4720 if (fs->within_session()) {
4724 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4725 source_path_map[fs->path()].push_back (fs);
4727 SeveralFileSources v;
4729 source_path_map.insert (make_pair (fs->path(), v));
4735 cerr << " fsources = " << total << endl;
4737 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4739 /* tell caller where we are */
4741 string old_path = i->first;
4743 callback (n, total, old_path);
4745 cerr << old_path << endl;
4749 switch (i->second.front()->type()) {
4750 case DataType::AUDIO:
4751 new_path = new_audio_source_path_for_embedded (old_path);
4754 case DataType::MIDI:
4755 /* XXX not implemented yet */
4759 if (new_path.empty()) {
4763 cerr << "Move " << old_path << " => " << new_path << endl;
4765 if (!copy_file (old_path, new_path)) {
4766 cerr << "failed !\n";
4770 /* make sure we stop looking in the external
4771 dir/folder. Remember, this is an all-or-nothing
4772 operations, it doesn't merge just some files.
4774 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4776 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4777 (*f)->set_path (new_path);
4782 save_state ("", false, false);
4788 bool accept_all_files (string const &, void *)
4794 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4796 /* 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.
4801 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4803 // old_path must be in within_session ()
4804 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4806 v.push_back (new_session_folder); /* full path */
4807 v.push_back (interchange_dir_name);
4808 v.push_back (new_session_name); /* just one directory/folder */
4809 v.push_back (typedir);
4810 v.push_back (Glib::path_get_basename (old_path));
4812 return Glib::build_filename (v);
4816 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4819 v.push_back (new_session_folder); /* full path */
4820 v.push_back (interchange_dir_name);
4821 v.push_back (new_session_name);
4822 v.push_back (ARDOUR::sound_dir_name);
4823 v.push_back (filename);
4825 return Glib::build_filename (v);
4829 Session::save_as (SaveAs& saveas)
4831 vector<string> files;
4832 string current_folder = Glib::path_get_dirname (_path);
4833 string new_folder = legalize_for_path (saveas.new_name);
4834 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4835 int64_t total_bytes = 0;
4839 int32_t internal_file_cnt = 0;
4841 vector<string> do_not_copy_extensions;
4842 do_not_copy_extensions.push_back (statefile_suffix);
4843 do_not_copy_extensions.push_back (pending_suffix);
4844 do_not_copy_extensions.push_back (backup_suffix);
4845 do_not_copy_extensions.push_back (temp_suffix);
4846 do_not_copy_extensions.push_back (history_suffix);
4848 /* get total size */
4850 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4852 /* need to clear this because
4853 * find_files_matching_filter() is cumulative
4858 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4860 all += files.size();
4862 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4864 g_stat ((*i).c_str(), &gsb);
4865 total_bytes += gsb.st_size;
4869 /* save old values so we can switch back if we are not switching to the new session */
4871 string old_path = _path;
4872 string old_name = _name;
4873 string old_snapshot = _current_snapshot_name;
4874 string old_sd = _session_dir->root_path();
4875 vector<string> old_search_path[DataType::num_types];
4876 string old_config_search_path[DataType::num_types];
4878 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4879 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4880 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4881 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4883 /* switch session directory */
4885 (*_session_dir) = to_dir;
4887 /* create new tree */
4889 if (!_session_dir->create()) {
4890 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4895 /* copy all relevant files. Find each location in session_dirs,
4896 * and copy files from there to target.
4899 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4901 /* need to clear this because
4902 * find_files_matching_filter() is cumulative
4907 const size_t prefix_len = (*sd).path.size();
4909 /* Work just on the files within this session dir */
4911 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4913 /* add dir separator to protect against collisions with
4914 * track names (e.g. track named "audiofiles" or
4918 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4919 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4920 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4922 /* copy all the files. Handling is different for media files
4923 than others because of the *silly* subtree we have below the interchange
4924 folder. That really was a bad idea, but I'm not fixing it as part of
4925 implementing ::save_as().
4928 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4930 std::string from = *i;
4933 string filename = Glib::path_get_basename (from);
4934 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4935 if (filename == ".DS_STORE") {
4940 if (from.find (audiofile_dir_string) != string::npos) {
4942 /* audio file: only copy if asked */
4944 if (saveas.include_media && saveas.copy_media) {
4946 string to = make_new_media_path (*i, to_dir, new_folder);
4948 info << "media file copying from " << from << " to " << to << endmsg;
4950 if (!copy_file (from, to)) {
4951 throw Glib::FileError (Glib::FileError::IO_ERROR,
4952 string_compose(_("\ncopying \"%1\" failed !"), from));
4956 /* we found media files inside the session folder */
4958 internal_file_cnt++;
4960 } else if (from.find (midifile_dir_string) != string::npos) {
4962 /* midi file: always copy unless
4963 * creating an empty new session
4966 if (saveas.include_media) {
4968 string to = make_new_media_path (*i, to_dir, new_folder);
4970 info << "media file copying from " << from << " to " << to << endmsg;
4972 if (!copy_file (from, to)) {
4973 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4977 /* we found media files inside the session folder */
4979 internal_file_cnt++;
4981 } else if (from.find (analysis_dir_string) != string::npos) {
4983 /* make sure analysis dir exists in
4984 * new session folder, but we're not
4985 * copying analysis files here, see
4989 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4994 /* normal non-media file. Don't copy state, history, etc.
4997 bool do_copy = true;
4999 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5000 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5001 /* end of filename matches extension, do not copy file */
5007 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
5008 /* don't copy peakfiles if
5009 * we're not copying media
5015 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
5017 info << "attempting to make directory/folder " << to << endmsg;
5019 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
5020 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
5023 info << "attempting to copy " << from << " to " << to << endmsg;
5025 if (!copy_file (from, to)) {
5026 throw Glib::FileError (Glib::FileError::IO_ERROR,
5027 string_compose(_("\ncopying \"%1\" failed !"), from));
5032 /* measure file size even if we're not going to copy so that our Progress
5033 signals are correct, since we included these do-not-copy files
5034 in the computation of the total size and file count.
5038 g_stat (from.c_str(), &gsb);
5039 copied += gsb.st_size;
5042 double fraction = (double) copied / total_bytes;
5044 bool keep_going = true;
5046 if (saveas.copy_media) {
5048 /* no need or expectation of this if
5049 * media is not being copied, because
5050 * it will be fast(ish).
5053 /* tell someone "X percent, file M of N"; M is one-based */
5055 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
5063 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
5069 /* copy optional folders, if any */
5071 string old = plugins_dir ();
5072 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5073 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5074 copy_files (old, newdir);
5077 old = externals_dir ();
5078 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5079 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5080 copy_files (old, newdir);
5083 old = automation_dir ();
5084 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5085 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5086 copy_files (old, newdir);
5089 if (saveas.include_media) {
5091 if (saveas.copy_media) {
5092 #ifndef PLATFORM_WINDOWS
5093 /* There are problems with analysis files on
5094 * Windows, because they used a colon in their
5095 * names as late as 4.0. Colons are not legal
5096 * under Windows even if NTFS allows them.
5098 * This is a tricky problem to solve so for
5099 * just don't copy these files. They will be
5100 * regenerated as-needed anyway, subject to the
5101 * existing issue that the filenames will be
5102 * rejected by Windows, which is a separate
5103 * problem (though related).
5106 /* only needed if we are copying media, since the
5107 * analysis data refers to media data
5110 old = analysis_dir ();
5111 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5112 string newdir = Glib::build_filename (to_dir, "analysis");
5113 copy_files (old, newdir);
5115 #endif /* PLATFORM_WINDOWS */
5120 set_snapshot_name (saveas.new_name);
5121 _name = saveas.new_name;
5123 if (saveas.include_media && !saveas.copy_media) {
5125 /* reset search paths of the new session (which we're pretending to be right now) to
5126 include the original session search path, so we can still find all audio.
5129 if (internal_file_cnt) {
5130 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5131 ensure_search_path_includes (*s, DataType::AUDIO);
5132 cerr << "be sure to include " << *s << " for audio" << endl;
5135 /* we do not do this for MIDI because we copy
5136 all MIDI files if saveas.include_media is
5142 bool was_dirty = dirty ();
5144 save_default_options ();
5146 if (saveas.copy_media && saveas.copy_external) {
5147 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5148 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5152 saveas.final_session_folder_name = _path;
5154 store_recent_sessions (_name, _path);
5156 if (!saveas.switch_to) {
5158 /* save the new state */
5160 save_state ("", false, false, !saveas.include_media);
5162 /* switch back to the way things were */
5166 set_snapshot_name (old_snapshot);
5168 (*_session_dir) = old_sd;
5174 if (internal_file_cnt) {
5175 /* reset these to their original values */
5176 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5177 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5182 /* prune session dirs, and update disk space statistics
5187 session_dirs.clear ();
5188 session_dirs.push_back (sp);
5189 refresh_disk_space ();
5191 _writable = exists_and_writable (_path);
5193 /* ensure that all existing tracks reset their current capture source paths
5195 reset_write_sources (true, true);
5197 /* creating new write sources marks the session as
5198 dirty. If the new session is empty, then
5199 save_state() thinks we're saving a template and will
5200 not mark the session as clean. So do that here,
5201 before we save state.
5204 if (!saveas.include_media) {
5205 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5208 save_state ("", false, false, !saveas.include_media);
5210 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5211 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5214 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5215 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5221 if (fs->within_session()) {
5222 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5223 fs->set_path (newpath);
5228 } catch (Glib::FileError& e) {
5230 saveas.failure_message = e.what();
5232 /* recursively remove all the directories */
5234 remove_directory (to_dir);
5242 saveas.failure_message = _("unknown reason");
5244 /* recursively remove all the directories */
5246 remove_directory (to_dir);
5256 static void set_progress (Progress* p, size_t n, size_t t)
5258 p->set_progress (float (n) / float(t));
5262 Session::archive_session (const std::string& dest,
5263 const std::string& name,
5264 ArchiveEncode compress_audio,
5265 FileArchive::CompressionLevel compression_level,
5266 bool only_used_sources,
5269 if (dest.empty () || name.empty ()) {
5273 /* We are going to temporarily change some source properties,
5274 * don't allow any concurrent saves (periodic or otherwise */
5275 Glib::Threads::Mutex::Lock lm (save_source_lock);
5277 disable_record (false);
5279 /* save current values */
5280 string old_path = _path;
5281 string old_name = _name;
5282 string old_snapshot = _current_snapshot_name;
5283 string old_sd = _session_dir->root_path();
5284 string old_config_search_path[DataType::num_types];
5285 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5286 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5288 /* ensure that session-path is included in search-path */
5290 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5291 if ((*sd).path == old_path) {
5299 /* create temporary dir to save session to */
5300 #ifdef PLATFORM_WINDOWS
5301 char tmp[256] = "C:\\TEMP\\";
5302 GetTempPath (sizeof (tmp), tmp);
5304 char const* tmp = getenv("TMPDIR");
5309 if ((strlen (tmp) + 21) > 1024) {
5314 strcpy (tmptpl, tmp);
5315 strcat (tmptpl, "ardourarchive-XXXXXX");
5316 char* tmpdir = g_mkdtemp (tmptpl);
5322 std::string to_dir = std::string (tmpdir);
5324 /* switch session directory temporarily */
5325 (*_session_dir) = to_dir;
5327 if (!_session_dir->create()) {
5328 (*_session_dir) = old_sd;
5329 remove_directory (to_dir);
5333 /* prepare archive */
5334 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5336 PBD::ScopedConnectionList progress_connection;
5337 PBD::FileArchive ar (archive);
5339 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5342 /* collect files to archive */
5343 std::map<string,string> filemap;
5345 vector<string> do_not_copy_extensions;
5346 do_not_copy_extensions.push_back (statefile_suffix);
5347 do_not_copy_extensions.push_back (pending_suffix);
5348 do_not_copy_extensions.push_back (backup_suffix);
5349 do_not_copy_extensions.push_back (temp_suffix);
5350 do_not_copy_extensions.push_back (history_suffix);
5352 vector<string> blacklist_dirs;
5353 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5354 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5355 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5356 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5357 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5358 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5360 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5361 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5362 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5364 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5365 if (only_used_sources) {
5366 playlists->sync_all_regions_with_regions ();
5367 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5370 /* collect audio sources for this session, calc total size for encoding
5371 * add option to only include *used* sources (see Session::cleanup_sources)
5373 size_t total_size = 0;
5375 Glib::Threads::Mutex::Lock lm (source_lock);
5377 /* build a list of used names */
5378 std::set<std::string> audio_file_names;
5379 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5380 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5381 if (!afs || afs->readable_length () == 0) {
5384 if (only_used_sources) {
5388 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5392 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5395 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5396 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5397 if (!afs || afs->readable_length () == 0) {
5401 if (only_used_sources) {
5405 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5410 std::string from = afs->path();
5412 if (compress_audio != NO_ENCODE) {
5413 total_size += afs->readable_length ();
5415 /* copy files as-is */
5416 if (!afs->within_session()) {
5417 string to = Glib::path_get_basename (from);
5419 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5420 * - avoid conflict with files existing in interchange
5421 * - avoid conflict with other embedded sources
5423 if (audio_file_names.find (to) == audio_file_names.end ()) {
5424 // we need a new name, add a '-<num>' before the '.<ext>'
5425 string bn = to.substr (0, to.find_last_of ('.'));
5426 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5427 to = bn + "-1" + ext;
5429 while (audio_file_names.find (to) == audio_file_names.end ()) {
5430 to = bump_name_once (to, '-');
5433 audio_file_names.insert (to);
5434 filemap[from] = make_new_audio_path (to, name, name);
5436 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5438 orig_origin[afs] = afs->origin ();
5439 afs->set_origin ("");
5442 filemap[from] = make_new_media_path (from, name, name);
5449 if (compress_audio != NO_ENCODE) {
5451 progress->set_progress (2); // set to "encoding"
5452 progress->set_progress (0);
5455 Glib::Threads::Mutex::Lock lm (source_lock);
5456 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5457 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5458 if (!afs || afs->readable_length () == 0) {
5462 if (only_used_sources) {
5466 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5471 orig_sources[afs] = afs->path();
5472 orig_gain[afs] = afs->gain();
5474 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5476 std::string channelsuffix = "";
5477 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5478 /* embedded external multi-channel files are converted to multiple-mono */
5479 channelsuffix = string_compose ("-c%1", afs->channel ());
5481 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5482 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5484 /* avoid name collisions of external files with same name */
5485 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5486 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5488 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5489 new_path = bump_name_once (new_path, '-');
5493 progress->descend ((float)afs->readable_length () / total_size);
5497 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5498 afs->replace_file (new_path);
5499 afs->set_gain (ns->gain(), true);
5502 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5506 progress->ascend ();
5512 progress->set_progress (-1); // set to "archiving"
5513 progress->set_progress (0);
5516 /* index files relevant for this session */
5517 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5518 vector<string> files;
5520 size_t prefix_len = (*sd).path.size();
5521 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5525 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5527 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5528 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5529 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5531 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5532 std::string from = *i;
5535 string filename = Glib::path_get_basename (from);
5536 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5537 if (filename == ".DS_STORE") {
5542 if (from.find (audiofile_dir_string) != string::npos) {
5544 } else if (from.find (midifile_dir_string) != string::npos) {
5545 filemap[from] = make_new_media_path (from, name, name);
5546 } else if (from.find (videofile_dir_string) != string::npos) {
5547 filemap[from] = make_new_media_path (from, name, name);
5549 bool do_copy = true;
5550 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5551 if (from.find (*v) != string::npos) {
5556 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5557 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5564 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5570 /* write session file */
5572 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5574 save_state (name, false, false, false, true, only_used_sources);
5576 save_default_options ();
5578 size_t prefix_len = _path.size();
5579 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5583 /* collect session-state files */
5584 vector<string> files;
5585 do_not_copy_extensions.clear ();
5586 do_not_copy_extensions.push_back (history_suffix);
5588 blacklist_dirs.clear ();
5589 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5591 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5592 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5593 std::string from = *i;
5594 bool do_copy = true;
5595 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5596 if (from.find (*v) != string::npos) {
5601 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5602 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5608 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5612 /* restore original values */
5615 set_snapshot_name (old_snapshot);
5616 (*_session_dir) = old_sd;
5617 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5618 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5620 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5621 i->first->set_origin (i->second);
5623 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5624 i->first->replace_file (i->second);
5626 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5627 i->first->set_gain (i->second, true);
5630 int rv = ar.create (filemap, compression_level);
5631 remove_directory (to_dir);
5637 Session::undo (uint32_t n)
5639 if (actively_recording()) {
5647 Session::redo (uint32_t n)
5649 if (actively_recording()) {