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 ControllableDescriptor::Gain:
3788 c = s->gain_control ();
3791 case ControllableDescriptor::Trim:
3792 c = s->trim_control ();
3795 case ControllableDescriptor::Solo:
3796 c = s->solo_control();
3799 case ControllableDescriptor::Mute:
3800 c = s->mute_control();
3803 case ControllableDescriptor::Recenable:
3804 c = s->rec_enable_control ();
3807 case ControllableDescriptor::PanDirection:
3808 c = s->pan_azimuth_control();
3811 case ControllableDescriptor::PanWidth:
3812 c = s->pan_width_control();
3815 case ControllableDescriptor::PanElevation:
3816 c = s->pan_elevation_control();
3819 case ControllableDescriptor::Balance:
3820 /* XXX simple pan control */
3823 case ControllableDescriptor::PluginParameter:
3825 uint32_t plugin = desc.target (0);
3826 uint32_t parameter_index = desc.target (1);
3828 /* revert to zero based counting */
3834 if (parameter_index > 0) {
3842 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3845 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3846 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3851 case ControllableDescriptor::SendGain: {
3852 uint32_t send = desc.target (0);
3859 c = r->send_level_controllable (send);
3864 /* relax and return a null pointer */
3872 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3875 Stateful::add_instant_xml (node, _path);
3878 if (write_to_config) {
3879 Config->add_instant_xml (node);
3884 Session::instant_xml (const string& node_name)
3886 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3887 if (get_disable_all_loaded_plugins ()) {
3891 return Stateful::instant_xml (node_name, _path);
3895 Session::save_history (string snapshot_name)
3903 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3904 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3908 if (snapshot_name.empty()) {
3909 snapshot_name = _current_snapshot_name;
3912 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3913 const string backup_filename = history_filename + backup_suffix;
3914 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3915 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3917 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3918 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3919 error << _("could not backup old history file, current history not saved") << endmsg;
3924 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3926 if (!tree.write (xml_path))
3928 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3930 if (g_remove (xml_path.c_str()) != 0) {
3931 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3932 xml_path, g_strerror (errno)) << endmsg;
3934 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3935 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3936 backup_path, g_strerror (errno)) << endmsg;
3946 Session::restore_history (string snapshot_name)
3950 if (snapshot_name.empty()) {
3951 snapshot_name = _current_snapshot_name;
3954 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3955 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3957 info << "Loading history from " << xml_path << endmsg;
3959 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3960 info << string_compose (_("%1: no history file \"%2\" for this session."),
3961 _name, xml_path) << endmsg;
3965 if (!tree.read (xml_path)) {
3966 error << string_compose (_("Could not understand session history file \"%1\""),
3967 xml_path) << endmsg;
3974 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3977 UndoTransaction* ut = new UndoTransaction ();
3983 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3984 !t->get_property ("tv-usec", tv_usec)) {
3988 ut->set_name (name);
3992 tv.tv_usec = tv_usec;
3993 ut->set_timestamp(tv);
3995 for (XMLNodeConstIterator child_it = t->children().begin();
3996 child_it != t->children().end(); child_it++)
3998 XMLNode *n = *child_it;
4001 if (n->name() == "MementoCommand" ||
4002 n->name() == "MementoUndoCommand" ||
4003 n->name() == "MementoRedoCommand") {
4005 if ((c = memento_command_factory(n))) {
4009 } else if (n->name() == "NoteDiffCommand") {
4010 PBD::ID id (n->property("midi-source")->value());
4011 boost::shared_ptr<MidiSource> midi_source =
4012 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
4014 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
4016 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
4019 } else if (n->name() == "SysExDiffCommand") {
4021 PBD::ID id (n->property("midi-source")->value());
4022 boost::shared_ptr<MidiSource> midi_source =
4023 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
4025 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
4027 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
4030 } else if (n->name() == "PatchChangeDiffCommand") {
4032 PBD::ID id (n->property("midi-source")->value());
4033 boost::shared_ptr<MidiSource> midi_source =
4034 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
4036 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
4038 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
4041 } else if (n->name() == "StatefulDiffCommand") {
4042 if ((c = stateful_diff_command_factory (n))) {
4043 ut->add_command (c);
4046 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
4057 Session::config_changed (std::string p, bool ours)
4063 if (p == "seamless-loop") {
4065 } else if (p == "rf-speed") {
4067 } else if (p == "auto-loop") {
4069 } else if (p == "session-monitoring") {
4071 } else if (p == "auto-input") {
4073 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4074 /* auto-input only makes a difference if we're rolling */
4075 set_track_monitor_input_status (!config.get_auto_input());
4078 } else if (p == "punch-in") {
4082 if ((location = _locations->auto_punch_location()) != 0) {
4084 if (config.get_punch_in ()) {
4085 auto_punch_start_changed (location);
4087 clear_events (SessionEvent::PunchIn);
4091 } else if (p == "punch-out") {
4095 if ((location = _locations->auto_punch_location()) != 0) {
4097 if (config.get_punch_out()) {
4098 auto_punch_end_changed (location);
4100 clear_events (SessionEvent::PunchOut);
4104 } else if (p == "edit-mode") {
4106 Glib::Threads::Mutex::Lock lm (playlists->lock);
4108 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4109 (*i)->set_edit_mode (Config->get_edit_mode ());
4112 } else if (p == "use-video-sync") {
4114 waiting_for_sync_offset = config.get_use_video_sync();
4116 } else if (p == "mmc-control") {
4118 //poke_midi_thread ();
4120 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4122 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4124 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4126 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4128 } else if (p == "midi-control") {
4130 //poke_midi_thread ();
4132 } else if (p == "raid-path") {
4134 setup_raid_path (config.get_raid_path());
4136 } else if (p == "timecode-format") {
4140 } else if (p == "video-pullup") {
4144 } else if (p == "seamless-loop") {
4146 if (play_loop && transport_rolling()) {
4147 // to reset diskstreams etc
4148 request_play_loop (true);
4151 } else if (p == "rf-speed") {
4153 cumulative_rf_motion = 0;
4156 } else if (p == "click-sound") {
4158 setup_click_sounds (1);
4160 } else if (p == "click-emphasis-sound") {
4162 setup_click_sounds (-1);
4164 } else if (p == "clicking") {
4166 if (Config->get_clicking()) {
4167 if (_click_io && click_data) { // don't require emphasis data
4174 } else if (p == "click-record-only") {
4176 _click_rec_only = Config->get_click_record_only();
4178 } else if (p == "click-gain") {
4181 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4184 } else if (p == "send-mtc") {
4186 if (Config->get_send_mtc ()) {
4187 /* mark us ready to send */
4188 next_quarter_frame_to_send = 0;
4191 } else if (p == "send-mmc") {
4193 _mmc->enable_send (Config->get_send_mmc ());
4194 if (Config->get_send_mmc ()) {
4195 /* re-initialize MMC */
4196 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4197 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4200 } else if (p == "jack-time-master") {
4202 engine().reset_timebase ();
4204 } else if (p == "native-file-header-format") {
4206 if (!first_file_header_format_reset) {
4207 reset_native_file_format ();
4210 first_file_header_format_reset = false;
4212 } else if (p == "native-file-data-format") {
4214 if (!first_file_data_format_reset) {
4215 reset_native_file_format ();
4218 first_file_data_format_reset = false;
4220 } else if (p == "external-sync") {
4221 if (!config.get_external_sync()) {
4222 drop_sync_source ();
4224 switch_to_sync_source (Config->get_sync_source());
4226 } else if (p == "denormal-model") {
4228 } else if (p == "history-depth") {
4229 set_history_depth (Config->get_history_depth());
4230 } else if (p == "remote-model") {
4231 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4234 } else if (p == "initial-program-change") {
4236 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4239 buf[0] = MIDI::program; // channel zero by default
4240 buf[1] = (Config->get_initial_program_change() & 0x7f);
4242 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4244 } else if (p == "solo-mute-override") {
4245 // catch_up_on_solo_mute_override ();
4246 } else if (p == "listen-position" || p == "pfl-position") {
4247 listen_position_changed ();
4248 } else if (p == "solo-control-is-listen-control") {
4249 solo_control_mode_changed ();
4250 } else if (p == "solo-mute-gain") {
4251 _solo_cut_control->Changed (true, Controllable::NoGroup);
4252 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4253 last_timecode_valid = false;
4254 } else if (p == "playback-buffer-seconds") {
4255 AudioSource::allocate_working_buffers (sample_rate());
4256 } else if (p == "ltc-source-port") {
4257 reconnect_ltc_input ();
4258 } else if (p == "ltc-sink-port") {
4259 reconnect_ltc_output ();
4260 } else if (p == "timecode-generator-offset") {
4261 ltc_tx_parse_offset();
4262 } else if (p == "auto-return-target-list") {
4263 follow_playhead_priority ();
4270 Session::set_history_depth (uint32_t d)
4272 _history.set_depth (d);
4275 /** Connect things to the MMC object */
4277 Session::setup_midi_machine_control ()
4279 _mmc = new MIDI::MachineControl;
4281 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4282 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4284 if (!async_out || !async_out) {
4288 /* XXXX argh, passing raw pointers back into libmidi++ */
4290 MIDI::Port* mmc_in = async_in.get();
4291 MIDI::Port* mmc_out = async_out.get();
4293 _mmc->set_ports (mmc_in, mmc_out);
4295 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4296 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4297 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4298 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4299 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4300 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4301 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4302 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4303 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4304 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4305 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4306 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4307 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4309 /* also handle MIDI SPP because its so common */
4311 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4312 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4313 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4316 boost::shared_ptr<Controllable>
4317 Session::solo_cut_control() const
4319 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4320 * controls in Ardour that currently get presented to the user in the GUI that require
4321 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4323 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4324 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4327 return _solo_cut_control;
4331 Session::save_snapshot_name (const std::string & n)
4333 /* assure Stateful::_instant_xml is loaded
4334 * add_instant_xml() only adds to existing data and defaults
4335 * to use an empty Tree otherwise
4337 instant_xml ("LastUsedSnapshot");
4339 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4340 last_used_snapshot->set_property ("name", n);
4341 add_instant_xml (*last_used_snapshot, false);
4345 Session::set_snapshot_name (const std::string & n)
4347 _current_snapshot_name = n;
4348 save_snapshot_name (n);
4352 Session::rename (const std::string& new_name)
4354 string legal_name = legalize_for_path (new_name);
4360 string const old_sources_root = _session_dir->sources_root();
4362 if (!_writable || (_state_of_the_state & CannotSave)) {
4363 error << _("Cannot rename read-only session.") << endmsg;
4364 return 0; // don't show "messed up" warning
4366 if (record_status() == Recording) {
4367 error << _("Cannot rename session while recording") << endmsg;
4368 return 0; // don't show "messed up" warning
4371 StateProtector stp (this);
4376 * interchange subdirectory
4380 * Backup files are left unchanged and not renamed.
4383 /* Windows requires that we close all files before attempting the
4384 * rename. This works on other platforms, but isn't necessary there.
4385 * Leave it in place for all platforms though, since it may help
4386 * catch issues that could arise if the way Source files work ever
4387 * change (since most developers are not using Windows).
4390 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4391 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4397 /* pass one: not 100% safe check that the new directory names don't
4401 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4405 /* this is a stupid hack because Glib::path_get_dirname() is
4406 * lexical-only, and so passing it /a/b/c/ gives a different
4407 * result than passing it /a/b/c ...
4410 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4411 oldstr = oldstr.substr (0, oldstr.length() - 1);
4414 string base = Glib::path_get_dirname (oldstr);
4416 newstr = Glib::build_filename (base, legal_name);
4418 cerr << "Looking for " << newstr << endl;
4420 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4421 cerr << " exists\n";
4430 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4436 /* this is a stupid hack because Glib::path_get_dirname() is
4437 * lexical-only, and so passing it /a/b/c/ gives a different
4438 * result than passing it /a/b/c ...
4441 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4442 oldstr = oldstr.substr (0, oldstr.length() - 1);
4445 string base = Glib::path_get_dirname (oldstr);
4446 newstr = Glib::build_filename (base, legal_name);
4448 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4450 cerr << "Rename " << oldstr << " => " << newstr << endl;
4451 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4452 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4453 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4457 /* Reset path in "session dirs" */
4462 /* reset primary SessionDirectory object */
4465 (*_session_dir) = newstr;
4470 /* now rename directory below session_dir/interchange */
4472 string old_interchange_dir;
4473 string new_interchange_dir;
4475 /* use newstr here because we renamed the path
4476 * (folder/directory) that used to be oldstr to newstr above
4479 v.push_back (newstr);
4480 v.push_back (interchange_dir_name);
4481 v.push_back (Glib::path_get_basename (oldstr));
4483 old_interchange_dir = Glib::build_filename (v);
4486 v.push_back (newstr);
4487 v.push_back (interchange_dir_name);
4488 v.push_back (legal_name);
4490 new_interchange_dir = Glib::build_filename (v);
4492 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4494 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4495 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4496 old_interchange_dir, new_interchange_dir,
4499 error << string_compose (_("renaming %s as %2 failed (%3)"),
4500 old_interchange_dir, new_interchange_dir,
4509 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4510 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4512 cerr << "Rename " << oldstr << " => " << newstr << endl;
4514 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4515 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4516 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4522 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4524 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4525 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4527 cerr << "Rename " << oldstr << " => " << newstr << endl;
4529 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4530 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4531 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4536 /* remove old name from recent sessions */
4537 remove_recent_sessions (_path);
4540 /* update file source paths */
4542 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4543 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4545 string p = fs->path ();
4546 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4548 SourceFactory::setup_peakfile(i->second, true);
4552 set_snapshot_name (new_name);
4557 /* save state again to get everything just right */
4559 save_state (_current_snapshot_name);
4561 /* add to recent sessions */
4563 store_recent_sessions (new_name, _path);
4569 Session::parse_stateful_loading_version (const std::string& version)
4571 if (version.empty ()) {
4572 /* no version implies very old version of Ardour */
4576 if (version.find ('.') != string::npos) {
4577 /* old school version format */
4578 if (version[0] == '2') {
4584 return string_to<int32_t>(version);
4589 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4591 bool found_sr = false;
4592 bool found_data_format = false;
4593 std::string version;
4594 program_version = "";
4596 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4600 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4604 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4607 xmlFreeParserCtxt(ctxt);
4611 xmlNodePtr node = xmlDocGetRootElement(doc);
4614 xmlFreeParserCtxt(ctxt);
4619 /* sample rate & version*/
4622 for (attr = node->properties; attr; attr = attr->next) {
4623 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4624 version = std::string ((char*)attr->children->content);
4626 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4627 sample_rate = atoi ((char*)attr->children->content);
4632 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4636 node = node->children;
4637 while (node != NULL) {
4638 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4639 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4641 program_version = string ((const char*)val);
4642 size_t sep = program_version.find_first_of("-");
4643 if (sep != string::npos) {
4644 program_version = program_version.substr (0, sep);
4649 if (strcmp((const char*) node->name, "Config")) {
4653 for (node = node->children; node; node = node->next) {
4654 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4655 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4657 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4660 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4662 found_data_format = true;
4663 } catch (PBD::unknown_enumeration& e) {}
4673 xmlFreeParserCtxt(ctxt);
4676 return (found_sr && found_data_format) ? 0 : 1;
4680 Session::get_snapshot_from_instant (const std::string& session_dir)
4682 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4684 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4689 if (!tree.read (instant_xml_path)) {
4693 XMLProperty const * prop;
4694 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4695 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4696 return prop->value();
4702 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4703 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4706 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4710 SourcePathMap source_path_map;
4712 boost::shared_ptr<AudioFileSource> afs;
4717 Glib::Threads::Mutex::Lock lm (source_lock);
4719 cerr << " total sources = " << sources.size();
4721 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4722 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4728 if (fs->within_session()) {
4732 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4733 source_path_map[fs->path()].push_back (fs);
4735 SeveralFileSources v;
4737 source_path_map.insert (make_pair (fs->path(), v));
4743 cerr << " fsources = " << total << endl;
4745 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4747 /* tell caller where we are */
4749 string old_path = i->first;
4751 callback (n, total, old_path);
4753 cerr << old_path << endl;
4757 switch (i->second.front()->type()) {
4758 case DataType::AUDIO:
4759 new_path = new_audio_source_path_for_embedded (old_path);
4762 case DataType::MIDI:
4763 /* XXX not implemented yet */
4767 if (new_path.empty()) {
4771 cerr << "Move " << old_path << " => " << new_path << endl;
4773 if (!copy_file (old_path, new_path)) {
4774 cerr << "failed !\n";
4778 /* make sure we stop looking in the external
4779 dir/folder. Remember, this is an all-or-nothing
4780 operations, it doesn't merge just some files.
4782 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4784 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4785 (*f)->set_path (new_path);
4790 save_state ("", false, false);
4796 bool accept_all_files (string const &, void *)
4802 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4804 /* 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.
4809 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4811 // old_path must be in within_session ()
4812 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4814 v.push_back (new_session_folder); /* full path */
4815 v.push_back (interchange_dir_name);
4816 v.push_back (new_session_name); /* just one directory/folder */
4817 v.push_back (typedir);
4818 v.push_back (Glib::path_get_basename (old_path));
4820 return Glib::build_filename (v);
4824 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4827 v.push_back (new_session_folder); /* full path */
4828 v.push_back (interchange_dir_name);
4829 v.push_back (new_session_name);
4830 v.push_back (ARDOUR::sound_dir_name);
4831 v.push_back (filename);
4833 return Glib::build_filename (v);
4837 Session::save_as (SaveAs& saveas)
4839 vector<string> files;
4840 string current_folder = Glib::path_get_dirname (_path);
4841 string new_folder = legalize_for_path (saveas.new_name);
4842 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4843 int64_t total_bytes = 0;
4847 int32_t internal_file_cnt = 0;
4849 vector<string> do_not_copy_extensions;
4850 do_not_copy_extensions.push_back (statefile_suffix);
4851 do_not_copy_extensions.push_back (pending_suffix);
4852 do_not_copy_extensions.push_back (backup_suffix);
4853 do_not_copy_extensions.push_back (temp_suffix);
4854 do_not_copy_extensions.push_back (history_suffix);
4856 /* get total size */
4858 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4860 /* need to clear this because
4861 * find_files_matching_filter() is cumulative
4866 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4868 all += files.size();
4870 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4872 g_stat ((*i).c_str(), &gsb);
4873 total_bytes += gsb.st_size;
4877 /* save old values so we can switch back if we are not switching to the new session */
4879 string old_path = _path;
4880 string old_name = _name;
4881 string old_snapshot = _current_snapshot_name;
4882 string old_sd = _session_dir->root_path();
4883 vector<string> old_search_path[DataType::num_types];
4884 string old_config_search_path[DataType::num_types];
4886 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4887 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4888 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4889 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4891 /* switch session directory */
4893 (*_session_dir) = to_dir;
4895 /* create new tree */
4897 if (!_session_dir->create()) {
4898 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4903 /* copy all relevant files. Find each location in session_dirs,
4904 * and copy files from there to target.
4907 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4909 /* need to clear this because
4910 * find_files_matching_filter() is cumulative
4915 const size_t prefix_len = (*sd).path.size();
4917 /* Work just on the files within this session dir */
4919 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4921 /* add dir separator to protect against collisions with
4922 * track names (e.g. track named "audiofiles" or
4926 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4927 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4928 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4930 /* copy all the files. Handling is different for media files
4931 than others because of the *silly* subtree we have below the interchange
4932 folder. That really was a bad idea, but I'm not fixing it as part of
4933 implementing ::save_as().
4936 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4938 std::string from = *i;
4941 string filename = Glib::path_get_basename (from);
4942 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4943 if (filename == ".DS_STORE") {
4948 if (from.find (audiofile_dir_string) != string::npos) {
4950 /* audio file: only copy if asked */
4952 if (saveas.include_media && saveas.copy_media) {
4954 string to = make_new_media_path (*i, to_dir, new_folder);
4956 info << "media file copying from " << from << " to " << to << endmsg;
4958 if (!copy_file (from, to)) {
4959 throw Glib::FileError (Glib::FileError::IO_ERROR,
4960 string_compose(_("\ncopying \"%1\" failed !"), from));
4964 /* we found media files inside the session folder */
4966 internal_file_cnt++;
4968 } else if (from.find (midifile_dir_string) != string::npos) {
4970 /* midi file: always copy unless
4971 * creating an empty new session
4974 if (saveas.include_media) {
4976 string to = make_new_media_path (*i, to_dir, new_folder);
4978 info << "media file copying from " << from << " to " << to << endmsg;
4980 if (!copy_file (from, to)) {
4981 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4985 /* we found media files inside the session folder */
4987 internal_file_cnt++;
4989 } else if (from.find (analysis_dir_string) != string::npos) {
4991 /* make sure analysis dir exists in
4992 * new session folder, but we're not
4993 * copying analysis files here, see
4997 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
5002 /* normal non-media file. Don't copy state, history, etc.
5005 bool do_copy = true;
5007 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5008 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5009 /* end of filename matches extension, do not copy file */
5015 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
5016 /* don't copy peakfiles if
5017 * we're not copying media
5023 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
5025 info << "attempting to make directory/folder " << to << endmsg;
5027 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
5028 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
5031 info << "attempting to copy " << from << " to " << to << endmsg;
5033 if (!copy_file (from, to)) {
5034 throw Glib::FileError (Glib::FileError::IO_ERROR,
5035 string_compose(_("\ncopying \"%1\" failed !"), from));
5040 /* measure file size even if we're not going to copy so that our Progress
5041 signals are correct, since we included these do-not-copy files
5042 in the computation of the total size and file count.
5046 g_stat (from.c_str(), &gsb);
5047 copied += gsb.st_size;
5050 double fraction = (double) copied / total_bytes;
5052 bool keep_going = true;
5054 if (saveas.copy_media) {
5056 /* no need or expectation of this if
5057 * media is not being copied, because
5058 * it will be fast(ish).
5061 /* tell someone "X percent, file M of N"; M is one-based */
5063 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
5071 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
5077 /* copy optional folders, if any */
5079 string old = plugins_dir ();
5080 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5081 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5082 copy_files (old, newdir);
5085 old = externals_dir ();
5086 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5087 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5088 copy_files (old, newdir);
5091 old = automation_dir ();
5092 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5093 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5094 copy_files (old, newdir);
5097 if (saveas.include_media) {
5099 if (saveas.copy_media) {
5100 #ifndef PLATFORM_WINDOWS
5101 /* There are problems with analysis files on
5102 * Windows, because they used a colon in their
5103 * names as late as 4.0. Colons are not legal
5104 * under Windows even if NTFS allows them.
5106 * This is a tricky problem to solve so for
5107 * just don't copy these files. They will be
5108 * regenerated as-needed anyway, subject to the
5109 * existing issue that the filenames will be
5110 * rejected by Windows, which is a separate
5111 * problem (though related).
5114 /* only needed if we are copying media, since the
5115 * analysis data refers to media data
5118 old = analysis_dir ();
5119 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5120 string newdir = Glib::build_filename (to_dir, "analysis");
5121 copy_files (old, newdir);
5123 #endif /* PLATFORM_WINDOWS */
5128 set_snapshot_name (saveas.new_name);
5129 _name = saveas.new_name;
5131 if (saveas.include_media && !saveas.copy_media) {
5133 /* reset search paths of the new session (which we're pretending to be right now) to
5134 include the original session search path, so we can still find all audio.
5137 if (internal_file_cnt) {
5138 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5139 ensure_search_path_includes (*s, DataType::AUDIO);
5140 cerr << "be sure to include " << *s << " for audio" << endl;
5143 /* we do not do this for MIDI because we copy
5144 all MIDI files if saveas.include_media is
5150 bool was_dirty = dirty ();
5152 save_default_options ();
5154 if (saveas.copy_media && saveas.copy_external) {
5155 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5156 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5160 saveas.final_session_folder_name = _path;
5162 store_recent_sessions (_name, _path);
5164 if (!saveas.switch_to) {
5166 /* save the new state */
5168 save_state ("", false, false, !saveas.include_media);
5170 /* switch back to the way things were */
5174 set_snapshot_name (old_snapshot);
5176 (*_session_dir) = old_sd;
5182 if (internal_file_cnt) {
5183 /* reset these to their original values */
5184 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5185 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5190 /* prune session dirs, and update disk space statistics
5195 session_dirs.clear ();
5196 session_dirs.push_back (sp);
5197 refresh_disk_space ();
5199 _writable = exists_and_writable (_path);
5201 /* ensure that all existing tracks reset their current capture source paths
5203 reset_write_sources (true, true);
5205 /* creating new write sources marks the session as
5206 dirty. If the new session is empty, then
5207 save_state() thinks we're saving a template and will
5208 not mark the session as clean. So do that here,
5209 before we save state.
5212 if (!saveas.include_media) {
5213 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5216 save_state ("", false, false, !saveas.include_media);
5218 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5219 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5222 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5223 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5229 if (fs->within_session()) {
5230 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5231 fs->set_path (newpath);
5236 } catch (Glib::FileError& e) {
5238 saveas.failure_message = e.what();
5240 /* recursively remove all the directories */
5242 remove_directory (to_dir);
5250 saveas.failure_message = _("unknown reason");
5252 /* recursively remove all the directories */
5254 remove_directory (to_dir);
5264 static void set_progress (Progress* p, size_t n, size_t t)
5266 p->set_progress (float (n) / float(t));
5270 Session::archive_session (const std::string& dest,
5271 const std::string& name,
5272 ArchiveEncode compress_audio,
5273 FileArchive::CompressionLevel compression_level,
5274 bool only_used_sources,
5277 if (dest.empty () || name.empty ()) {
5281 /* We are going to temporarily change some source properties,
5282 * don't allow any concurrent saves (periodic or otherwise */
5283 Glib::Threads::Mutex::Lock lm (save_source_lock);
5285 disable_record (false);
5287 /* save current values */
5288 string old_path = _path;
5289 string old_name = _name;
5290 string old_snapshot = _current_snapshot_name;
5291 string old_sd = _session_dir->root_path();
5292 string old_config_search_path[DataType::num_types];
5293 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5294 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5296 /* ensure that session-path is included in search-path */
5298 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5299 if ((*sd).path == old_path) {
5307 /* create temporary dir to save session to */
5308 #ifdef PLATFORM_WINDOWS
5309 char tmp[256] = "C:\\TEMP\\";
5310 GetTempPath (sizeof (tmp), tmp);
5312 char const* tmp = getenv("TMPDIR");
5317 if ((strlen (tmp) + 21) > 1024) {
5322 strcpy (tmptpl, tmp);
5323 strcat (tmptpl, "ardourarchive-XXXXXX");
5324 char* tmpdir = g_mkdtemp (tmptpl);
5330 std::string to_dir = std::string (tmpdir);
5332 /* switch session directory temporarily */
5333 (*_session_dir) = to_dir;
5335 if (!_session_dir->create()) {
5336 (*_session_dir) = old_sd;
5337 remove_directory (to_dir);
5341 /* prepare archive */
5342 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5344 PBD::ScopedConnectionList progress_connection;
5345 PBD::FileArchive ar (archive);
5347 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5350 /* collect files to archive */
5351 std::map<string,string> filemap;
5353 vector<string> do_not_copy_extensions;
5354 do_not_copy_extensions.push_back (statefile_suffix);
5355 do_not_copy_extensions.push_back (pending_suffix);
5356 do_not_copy_extensions.push_back (backup_suffix);
5357 do_not_copy_extensions.push_back (temp_suffix);
5358 do_not_copy_extensions.push_back (history_suffix);
5360 vector<string> blacklist_dirs;
5361 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5362 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5363 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5364 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5365 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5366 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5368 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5369 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5370 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5372 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5373 if (only_used_sources) {
5374 playlists->sync_all_regions_with_regions ();
5375 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5378 /* collect audio sources for this session, calc total size for encoding
5379 * add option to only include *used* sources (see Session::cleanup_sources)
5381 size_t total_size = 0;
5383 Glib::Threads::Mutex::Lock lm (source_lock);
5385 /* build a list of used names */
5386 std::set<std::string> audio_file_names;
5387 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5388 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5389 if (!afs || afs->readable_length () == 0) {
5392 if (only_used_sources) {
5396 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5400 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5403 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5404 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5405 if (!afs || afs->readable_length () == 0) {
5409 if (only_used_sources) {
5413 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5418 std::string from = afs->path();
5420 if (compress_audio != NO_ENCODE) {
5421 total_size += afs->readable_length ();
5423 /* copy files as-is */
5424 if (!afs->within_session()) {
5425 string to = Glib::path_get_basename (from);
5427 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5428 * - avoid conflict with files existing in interchange
5429 * - avoid conflict with other embedded sources
5431 if (audio_file_names.find (to) == audio_file_names.end ()) {
5432 // we need a new name, add a '-<num>' before the '.<ext>'
5433 string bn = to.substr (0, to.find_last_of ('.'));
5434 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5435 to = bn + "-1" + ext;
5437 while (audio_file_names.find (to) == audio_file_names.end ()) {
5438 to = bump_name_once (to, '-');
5441 audio_file_names.insert (to);
5442 filemap[from] = make_new_audio_path (to, name, name);
5444 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5446 orig_origin[afs] = afs->origin ();
5447 afs->set_origin ("");
5450 filemap[from] = make_new_media_path (from, name, name);
5457 if (compress_audio != NO_ENCODE) {
5459 progress->set_progress (2); // set to "encoding"
5460 progress->set_progress (0);
5463 Glib::Threads::Mutex::Lock lm (source_lock);
5464 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5465 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5466 if (!afs || afs->readable_length () == 0) {
5470 if (only_used_sources) {
5474 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5479 orig_sources[afs] = afs->path();
5480 orig_gain[afs] = afs->gain();
5482 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5484 std::string channelsuffix = "";
5485 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5486 /* embedded external multi-channel files are converted to multiple-mono */
5487 channelsuffix = string_compose ("-c%1", afs->channel ());
5489 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5490 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5492 /* avoid name collisions of external files with same name */
5493 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5494 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5496 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5497 new_path = bump_name_once (new_path, '-');
5501 progress->descend ((float)afs->readable_length () / total_size);
5505 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5506 afs->replace_file (new_path);
5507 afs->set_gain (ns->gain(), true);
5510 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5514 progress->ascend ();
5520 progress->set_progress (-1); // set to "archiving"
5521 progress->set_progress (0);
5524 /* index files relevant for this session */
5525 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5526 vector<string> files;
5528 size_t prefix_len = (*sd).path.size();
5529 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5533 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5535 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5536 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5537 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5539 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5540 std::string from = *i;
5543 string filename = Glib::path_get_basename (from);
5544 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5545 if (filename == ".DS_STORE") {
5550 if (from.find (audiofile_dir_string) != string::npos) {
5552 } else if (from.find (midifile_dir_string) != string::npos) {
5553 filemap[from] = make_new_media_path (from, name, name);
5554 } else if (from.find (videofile_dir_string) != string::npos) {
5555 filemap[from] = make_new_media_path (from, name, name);
5557 bool do_copy = true;
5558 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5559 if (from.find (*v) != string::npos) {
5564 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5565 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5572 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5578 /* write session file */
5580 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5582 save_state (name, false, false, false, true, only_used_sources);
5584 save_default_options ();
5586 size_t prefix_len = _path.size();
5587 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5591 /* collect session-state files */
5592 vector<string> files;
5593 do_not_copy_extensions.clear ();
5594 do_not_copy_extensions.push_back (history_suffix);
5596 blacklist_dirs.clear ();
5597 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5599 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5600 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5601 std::string from = *i;
5602 bool do_copy = true;
5603 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5604 if (from.find (*v) != string::npos) {
5609 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5610 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5616 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5620 /* restore original values */
5623 set_snapshot_name (old_snapshot);
5624 (*_session_dir) = old_sd;
5625 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5626 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5628 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5629 i->first->set_origin (i->second);
5631 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5632 i->first->replace_file (i->second);
5634 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5635 i->first->set_gain (i->second, true);
5638 int rv = ar.create (filemap, compression_level);
5639 remove_directory (to_dir);
5645 Session::undo (uint32_t n)
5647 if (actively_recording()) {
5655 Session::redo (uint32_t n)
5657 if (actively_recording()) {