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) {
3982 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3983 !t->get_property ("tv-usec", tv_usec)) {
3987 UndoTransaction* ut = new UndoTransaction ();
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 == "auto-loop") {
4065 } else if (p == "session-monitoring") {
4067 } else if (p == "auto-input") {
4069 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4070 /* auto-input only makes a difference if we're rolling */
4071 set_track_monitor_input_status (!config.get_auto_input());
4074 } else if (p == "punch-in") {
4078 if ((location = _locations->auto_punch_location()) != 0) {
4080 if (config.get_punch_in ()) {
4081 auto_punch_start_changed (location);
4083 clear_events (SessionEvent::PunchIn);
4087 } else if (p == "punch-out") {
4091 if ((location = _locations->auto_punch_location()) != 0) {
4093 if (config.get_punch_out()) {
4094 auto_punch_end_changed (location);
4096 clear_events (SessionEvent::PunchOut);
4100 } else if (p == "edit-mode") {
4102 Glib::Threads::Mutex::Lock lm (playlists->lock);
4104 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4105 (*i)->set_edit_mode (Config->get_edit_mode ());
4108 } else if (p == "use-video-sync") {
4110 waiting_for_sync_offset = config.get_use_video_sync();
4112 } else if (p == "mmc-control") {
4114 //poke_midi_thread ();
4116 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4118 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4120 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4122 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4124 } else if (p == "midi-control") {
4126 //poke_midi_thread ();
4128 } else if (p == "raid-path") {
4130 setup_raid_path (config.get_raid_path());
4132 } else if (p == "timecode-format") {
4136 } else if (p == "video-pullup") {
4140 } else if (p == "seamless-loop") {
4142 if (play_loop && transport_rolling()) {
4143 // to reset diskstreams etc
4144 request_play_loop (true);
4147 } else if (p == "rf-speed") {
4149 cumulative_rf_motion = 0;
4152 } else if (p == "click-sound") {
4154 setup_click_sounds (1);
4156 } else if (p == "click-emphasis-sound") {
4158 setup_click_sounds (-1);
4160 } else if (p == "clicking") {
4162 if (Config->get_clicking()) {
4163 if (_click_io && click_data) { // don't require emphasis data
4170 } else if (p == "click-record-only") {
4172 _click_rec_only = Config->get_click_record_only();
4174 } else if (p == "click-gain") {
4177 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4180 } else if (p == "send-mtc") {
4182 if (Config->get_send_mtc ()) {
4183 /* mark us ready to send */
4184 next_quarter_frame_to_send = 0;
4187 } else if (p == "send-mmc") {
4189 _mmc->enable_send (Config->get_send_mmc ());
4190 if (Config->get_send_mmc ()) {
4191 /* re-initialize MMC */
4192 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4193 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4196 } else if (p == "jack-time-master") {
4198 engine().reset_timebase ();
4200 } else if (p == "native-file-header-format") {
4202 if (!first_file_header_format_reset) {
4203 reset_native_file_format ();
4206 first_file_header_format_reset = false;
4208 } else if (p == "native-file-data-format") {
4210 if (!first_file_data_format_reset) {
4211 reset_native_file_format ();
4214 first_file_data_format_reset = false;
4216 } else if (p == "external-sync") {
4217 if (!config.get_external_sync()) {
4218 drop_sync_source ();
4220 switch_to_sync_source (Config->get_sync_source());
4222 } else if (p == "denormal-model") {
4224 } else if (p == "history-depth") {
4225 set_history_depth (Config->get_history_depth());
4226 } else if (p == "remote-model") {
4227 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4230 } else if (p == "initial-program-change") {
4232 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4235 buf[0] = MIDI::program; // channel zero by default
4236 buf[1] = (Config->get_initial_program_change() & 0x7f);
4238 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4240 } else if (p == "solo-mute-override") {
4241 // catch_up_on_solo_mute_override ();
4242 } else if (p == "listen-position" || p == "pfl-position") {
4243 listen_position_changed ();
4244 } else if (p == "solo-control-is-listen-control") {
4245 solo_control_mode_changed ();
4246 } else if (p == "solo-mute-gain") {
4247 _solo_cut_control->Changed (true, Controllable::NoGroup);
4248 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4249 last_timecode_valid = false;
4250 } else if (p == "playback-buffer-seconds") {
4251 AudioSource::allocate_working_buffers (sample_rate());
4252 } else if (p == "ltc-source-port") {
4253 reconnect_ltc_input ();
4254 } else if (p == "ltc-sink-port") {
4255 reconnect_ltc_output ();
4256 } else if (p == "timecode-generator-offset") {
4257 ltc_tx_parse_offset();
4258 } else if (p == "auto-return-target-list") {
4259 follow_playhead_priority ();
4266 Session::set_history_depth (uint32_t d)
4268 _history.set_depth (d);
4271 /** Connect things to the MMC object */
4273 Session::setup_midi_machine_control ()
4275 _mmc = new MIDI::MachineControl;
4277 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4278 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4280 if (!async_out || !async_out) {
4284 /* XXXX argh, passing raw pointers back into libmidi++ */
4286 MIDI::Port* mmc_in = async_in.get();
4287 MIDI::Port* mmc_out = async_out.get();
4289 _mmc->set_ports (mmc_in, mmc_out);
4291 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4292 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4293 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4294 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4295 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4296 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4297 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4298 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4299 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4300 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4301 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4302 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4303 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4305 /* also handle MIDI SPP because its so common */
4307 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4308 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4309 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4312 boost::shared_ptr<Controllable>
4313 Session::solo_cut_control() const
4315 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4316 * controls in Ardour that currently get presented to the user in the GUI that require
4317 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4319 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4320 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4323 return _solo_cut_control;
4327 Session::save_snapshot_name (const std::string & n)
4329 /* assure Stateful::_instant_xml is loaded
4330 * add_instant_xml() only adds to existing data and defaults
4331 * to use an empty Tree otherwise
4333 instant_xml ("LastUsedSnapshot");
4335 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4336 last_used_snapshot->set_property ("name", n);
4337 add_instant_xml (*last_used_snapshot, false);
4341 Session::set_snapshot_name (const std::string & n)
4343 _current_snapshot_name = n;
4344 save_snapshot_name (n);
4348 Session::rename (const std::string& new_name)
4350 string legal_name = legalize_for_path (new_name);
4356 string const old_sources_root = _session_dir->sources_root();
4358 if (!_writable || (_state_of_the_state & CannotSave)) {
4359 error << _("Cannot rename read-only session.") << endmsg;
4360 return 0; // don't show "messed up" warning
4362 if (record_status() == Recording) {
4363 error << _("Cannot rename session while recording") << endmsg;
4364 return 0; // don't show "messed up" warning
4367 StateProtector stp (this);
4372 * interchange subdirectory
4376 * Backup files are left unchanged and not renamed.
4379 /* Windows requires that we close all files before attempting the
4380 * rename. This works on other platforms, but isn't necessary there.
4381 * Leave it in place for all platforms though, since it may help
4382 * catch issues that could arise if the way Source files work ever
4383 * change (since most developers are not using Windows).
4386 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4387 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4393 /* pass one: not 100% safe check that the new directory names don't
4397 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4401 /* this is a stupid hack because Glib::path_get_dirname() is
4402 * lexical-only, and so passing it /a/b/c/ gives a different
4403 * result than passing it /a/b/c ...
4406 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4407 oldstr = oldstr.substr (0, oldstr.length() - 1);
4410 string base = Glib::path_get_dirname (oldstr);
4412 newstr = Glib::build_filename (base, legal_name);
4414 cerr << "Looking for " << newstr << endl;
4416 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4417 cerr << " exists\n";
4426 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4432 /* this is a stupid hack because Glib::path_get_dirname() is
4433 * lexical-only, and so passing it /a/b/c/ gives a different
4434 * result than passing it /a/b/c ...
4437 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4438 oldstr = oldstr.substr (0, oldstr.length() - 1);
4441 string base = Glib::path_get_dirname (oldstr);
4442 newstr = Glib::build_filename (base, legal_name);
4444 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4446 cerr << "Rename " << oldstr << " => " << newstr << endl;
4447 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4448 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4449 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4453 /* Reset path in "session dirs" */
4458 /* reset primary SessionDirectory object */
4461 (*_session_dir) = newstr;
4466 /* now rename directory below session_dir/interchange */
4468 string old_interchange_dir;
4469 string new_interchange_dir;
4471 /* use newstr here because we renamed the path
4472 * (folder/directory) that used to be oldstr to newstr above
4475 v.push_back (newstr);
4476 v.push_back (interchange_dir_name);
4477 v.push_back (Glib::path_get_basename (oldstr));
4479 old_interchange_dir = Glib::build_filename (v);
4482 v.push_back (newstr);
4483 v.push_back (interchange_dir_name);
4484 v.push_back (legal_name);
4486 new_interchange_dir = Glib::build_filename (v);
4488 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4490 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4491 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4492 old_interchange_dir, new_interchange_dir,
4495 error << string_compose (_("renaming %s as %2 failed (%3)"),
4496 old_interchange_dir, new_interchange_dir,
4505 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4506 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4508 cerr << "Rename " << oldstr << " => " << newstr << endl;
4510 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4511 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4512 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4518 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4520 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4521 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4523 cerr << "Rename " << oldstr << " => " << newstr << endl;
4525 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4526 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4527 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4532 /* remove old name from recent sessions */
4533 remove_recent_sessions (_path);
4536 /* update file source paths */
4538 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4539 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4541 string p = fs->path ();
4542 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4544 SourceFactory::setup_peakfile(i->second, true);
4548 set_snapshot_name (new_name);
4553 /* save state again to get everything just right */
4555 save_state (_current_snapshot_name);
4557 /* add to recent sessions */
4559 store_recent_sessions (new_name, _path);
4565 Session::parse_stateful_loading_version (const std::string& version)
4567 if (version.empty ()) {
4568 /* no version implies very old version of Ardour */
4572 if (version.find ('.') != string::npos) {
4573 /* old school version format */
4574 if (version[0] == '2') {
4580 return string_to<int32_t>(version);
4585 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4587 bool found_sr = false;
4588 bool found_data_format = false;
4589 std::string version;
4590 program_version = "";
4592 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4596 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4600 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4603 xmlFreeParserCtxt(ctxt);
4607 xmlNodePtr node = xmlDocGetRootElement(doc);
4610 xmlFreeParserCtxt(ctxt);
4615 /* sample rate & version*/
4618 for (attr = node->properties; attr; attr = attr->next) {
4619 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4620 version = std::string ((char*)attr->children->content);
4622 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4623 sample_rate = atoi ((char*)attr->children->content);
4628 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4632 node = node->children;
4633 while (node != NULL) {
4634 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4635 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4637 program_version = string ((const char*)val);
4638 size_t sep = program_version.find_first_of("-");
4639 if (sep != string::npos) {
4640 program_version = program_version.substr (0, sep);
4645 if (strcmp((const char*) node->name, "Config")) {
4649 for (node = node->children; node; node = node->next) {
4650 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4651 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4653 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4656 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4658 found_data_format = true;
4659 } catch (PBD::unknown_enumeration& e) {}
4669 xmlFreeParserCtxt(ctxt);
4672 return (found_sr && found_data_format) ? 0 : 1;
4676 Session::get_snapshot_from_instant (const std::string& session_dir)
4678 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4680 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4685 if (!tree.read (instant_xml_path)) {
4689 XMLProperty const * prop;
4690 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4691 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4692 return prop->value();
4698 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4699 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4702 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4706 SourcePathMap source_path_map;
4708 boost::shared_ptr<AudioFileSource> afs;
4713 Glib::Threads::Mutex::Lock lm (source_lock);
4715 cerr << " total sources = " << sources.size();
4717 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4718 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4724 if (fs->within_session()) {
4728 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4729 source_path_map[fs->path()].push_back (fs);
4731 SeveralFileSources v;
4733 source_path_map.insert (make_pair (fs->path(), v));
4739 cerr << " fsources = " << total << endl;
4741 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4743 /* tell caller where we are */
4745 string old_path = i->first;
4747 callback (n, total, old_path);
4749 cerr << old_path << endl;
4753 switch (i->second.front()->type()) {
4754 case DataType::AUDIO:
4755 new_path = new_audio_source_path_for_embedded (old_path);
4758 case DataType::MIDI:
4759 /* XXX not implemented yet */
4763 if (new_path.empty()) {
4767 cerr << "Move " << old_path << " => " << new_path << endl;
4769 if (!copy_file (old_path, new_path)) {
4770 cerr << "failed !\n";
4774 /* make sure we stop looking in the external
4775 dir/folder. Remember, this is an all-or-nothing
4776 operations, it doesn't merge just some files.
4778 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4780 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4781 (*f)->set_path (new_path);
4786 save_state ("", false, false);
4792 bool accept_all_files (string const &, void *)
4798 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4800 /* 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.
4805 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4807 // old_path must be in within_session ()
4808 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4810 v.push_back (new_session_folder); /* full path */
4811 v.push_back (interchange_dir_name);
4812 v.push_back (new_session_name); /* just one directory/folder */
4813 v.push_back (typedir);
4814 v.push_back (Glib::path_get_basename (old_path));
4816 return Glib::build_filename (v);
4820 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4823 v.push_back (new_session_folder); /* full path */
4824 v.push_back (interchange_dir_name);
4825 v.push_back (new_session_name);
4826 v.push_back (ARDOUR::sound_dir_name);
4827 v.push_back (filename);
4829 return Glib::build_filename (v);
4833 Session::save_as (SaveAs& saveas)
4835 vector<string> files;
4836 string current_folder = Glib::path_get_dirname (_path);
4837 string new_folder = legalize_for_path (saveas.new_name);
4838 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4839 int64_t total_bytes = 0;
4843 int32_t internal_file_cnt = 0;
4845 vector<string> do_not_copy_extensions;
4846 do_not_copy_extensions.push_back (statefile_suffix);
4847 do_not_copy_extensions.push_back (pending_suffix);
4848 do_not_copy_extensions.push_back (backup_suffix);
4849 do_not_copy_extensions.push_back (temp_suffix);
4850 do_not_copy_extensions.push_back (history_suffix);
4852 /* get total size */
4854 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4856 /* need to clear this because
4857 * find_files_matching_filter() is cumulative
4862 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4864 all += files.size();
4866 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4868 g_stat ((*i).c_str(), &gsb);
4869 total_bytes += gsb.st_size;
4873 /* save old values so we can switch back if we are not switching to the new session */
4875 string old_path = _path;
4876 string old_name = _name;
4877 string old_snapshot = _current_snapshot_name;
4878 string old_sd = _session_dir->root_path();
4879 vector<string> old_search_path[DataType::num_types];
4880 string old_config_search_path[DataType::num_types];
4882 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4883 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4884 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4885 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4887 /* switch session directory */
4889 (*_session_dir) = to_dir;
4891 /* create new tree */
4893 if (!_session_dir->create()) {
4894 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4899 /* copy all relevant files. Find each location in session_dirs,
4900 * and copy files from there to target.
4903 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4905 /* need to clear this because
4906 * find_files_matching_filter() is cumulative
4911 const size_t prefix_len = (*sd).path.size();
4913 /* Work just on the files within this session dir */
4915 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4917 /* add dir separator to protect against collisions with
4918 * track names (e.g. track named "audiofiles" or
4922 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4923 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4924 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4926 /* copy all the files. Handling is different for media files
4927 than others because of the *silly* subtree we have below the interchange
4928 folder. That really was a bad idea, but I'm not fixing it as part of
4929 implementing ::save_as().
4932 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4934 std::string from = *i;
4937 string filename = Glib::path_get_basename (from);
4938 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4939 if (filename == ".DS_STORE") {
4944 if (from.find (audiofile_dir_string) != string::npos) {
4946 /* audio file: only copy if asked */
4948 if (saveas.include_media && saveas.copy_media) {
4950 string to = make_new_media_path (*i, to_dir, new_folder);
4952 info << "media file copying from " << from << " to " << to << endmsg;
4954 if (!copy_file (from, to)) {
4955 throw Glib::FileError (Glib::FileError::IO_ERROR,
4956 string_compose(_("\ncopying \"%1\" failed !"), from));
4960 /* we found media files inside the session folder */
4962 internal_file_cnt++;
4964 } else if (from.find (midifile_dir_string) != string::npos) {
4966 /* midi file: always copy unless
4967 * creating an empty new session
4970 if (saveas.include_media) {
4972 string to = make_new_media_path (*i, to_dir, new_folder);
4974 info << "media file copying from " << from << " to " << to << endmsg;
4976 if (!copy_file (from, to)) {
4977 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4981 /* we found media files inside the session folder */
4983 internal_file_cnt++;
4985 } else if (from.find (analysis_dir_string) != string::npos) {
4987 /* make sure analysis dir exists in
4988 * new session folder, but we're not
4989 * copying analysis files here, see
4993 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4998 /* normal non-media file. Don't copy state, history, etc.
5001 bool do_copy = true;
5003 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5004 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5005 /* end of filename matches extension, do not copy file */
5011 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
5012 /* don't copy peakfiles if
5013 * we're not copying media
5019 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
5021 info << "attempting to make directory/folder " << to << endmsg;
5023 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
5024 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
5027 info << "attempting to copy " << from << " to " << to << endmsg;
5029 if (!copy_file (from, to)) {
5030 throw Glib::FileError (Glib::FileError::IO_ERROR,
5031 string_compose(_("\ncopying \"%1\" failed !"), from));
5036 /* measure file size even if we're not going to copy so that our Progress
5037 signals are correct, since we included these do-not-copy files
5038 in the computation of the total size and file count.
5042 g_stat (from.c_str(), &gsb);
5043 copied += gsb.st_size;
5046 double fraction = (double) copied / total_bytes;
5048 bool keep_going = true;
5050 if (saveas.copy_media) {
5052 /* no need or expectation of this if
5053 * media is not being copied, because
5054 * it will be fast(ish).
5057 /* tell someone "X percent, file M of N"; M is one-based */
5059 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
5067 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
5073 /* copy optional folders, if any */
5075 string old = plugins_dir ();
5076 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5077 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5078 copy_files (old, newdir);
5081 old = externals_dir ();
5082 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5083 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5084 copy_files (old, newdir);
5087 old = automation_dir ();
5088 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5089 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5090 copy_files (old, newdir);
5093 if (saveas.include_media) {
5095 if (saveas.copy_media) {
5096 #ifndef PLATFORM_WINDOWS
5097 /* There are problems with analysis files on
5098 * Windows, because they used a colon in their
5099 * names as late as 4.0. Colons are not legal
5100 * under Windows even if NTFS allows them.
5102 * This is a tricky problem to solve so for
5103 * just don't copy these files. They will be
5104 * regenerated as-needed anyway, subject to the
5105 * existing issue that the filenames will be
5106 * rejected by Windows, which is a separate
5107 * problem (though related).
5110 /* only needed if we are copying media, since the
5111 * analysis data refers to media data
5114 old = analysis_dir ();
5115 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5116 string newdir = Glib::build_filename (to_dir, "analysis");
5117 copy_files (old, newdir);
5119 #endif /* PLATFORM_WINDOWS */
5124 set_snapshot_name (saveas.new_name);
5125 _name = saveas.new_name;
5127 if (saveas.include_media && !saveas.copy_media) {
5129 /* reset search paths of the new session (which we're pretending to be right now) to
5130 include the original session search path, so we can still find all audio.
5133 if (internal_file_cnt) {
5134 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5135 ensure_search_path_includes (*s, DataType::AUDIO);
5136 cerr << "be sure to include " << *s << " for audio" << endl;
5139 /* we do not do this for MIDI because we copy
5140 all MIDI files if saveas.include_media is
5146 bool was_dirty = dirty ();
5148 save_default_options ();
5150 if (saveas.copy_media && saveas.copy_external) {
5151 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5152 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5156 saveas.final_session_folder_name = _path;
5158 store_recent_sessions (_name, _path);
5160 if (!saveas.switch_to) {
5162 /* save the new state */
5164 save_state ("", false, false, !saveas.include_media);
5166 /* switch back to the way things were */
5170 set_snapshot_name (old_snapshot);
5172 (*_session_dir) = old_sd;
5178 if (internal_file_cnt) {
5179 /* reset these to their original values */
5180 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5181 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5186 /* prune session dirs, and update disk space statistics
5191 session_dirs.clear ();
5192 session_dirs.push_back (sp);
5193 refresh_disk_space ();
5195 _writable = exists_and_writable (_path);
5197 /* ensure that all existing tracks reset their current capture source paths
5199 reset_write_sources (true, true);
5201 /* creating new write sources marks the session as
5202 dirty. If the new session is empty, then
5203 save_state() thinks we're saving a template and will
5204 not mark the session as clean. So do that here,
5205 before we save state.
5208 if (!saveas.include_media) {
5209 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5212 save_state ("", false, false, !saveas.include_media);
5214 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5215 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5218 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5219 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5225 if (fs->within_session()) {
5226 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5227 fs->set_path (newpath);
5232 } catch (Glib::FileError& e) {
5234 saveas.failure_message = e.what();
5236 /* recursively remove all the directories */
5238 remove_directory (to_dir);
5246 saveas.failure_message = _("unknown reason");
5248 /* recursively remove all the directories */
5250 remove_directory (to_dir);
5260 static void set_progress (Progress* p, size_t n, size_t t)
5262 p->set_progress (float (n) / float(t));
5266 Session::archive_session (const std::string& dest,
5267 const std::string& name,
5268 ArchiveEncode compress_audio,
5269 FileArchive::CompressionLevel compression_level,
5270 bool only_used_sources,
5273 if (dest.empty () || name.empty ()) {
5277 /* We are going to temporarily change some source properties,
5278 * don't allow any concurrent saves (periodic or otherwise */
5279 Glib::Threads::Mutex::Lock lm (save_source_lock);
5281 disable_record (false);
5283 /* save current values */
5284 string old_path = _path;
5285 string old_name = _name;
5286 string old_snapshot = _current_snapshot_name;
5287 string old_sd = _session_dir->root_path();
5288 string old_config_search_path[DataType::num_types];
5289 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5290 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5292 /* ensure that session-path is included in search-path */
5294 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5295 if ((*sd).path == old_path) {
5303 /* create temporary dir to save session to */
5304 #ifdef PLATFORM_WINDOWS
5305 char tmp[256] = "C:\\TEMP\\";
5306 GetTempPath (sizeof (tmp), tmp);
5308 char const* tmp = getenv("TMPDIR");
5313 if ((strlen (tmp) + 21) > 1024) {
5318 strcpy (tmptpl, tmp);
5319 strcat (tmptpl, "ardourarchive-XXXXXX");
5320 char* tmpdir = g_mkdtemp (tmptpl);
5326 std::string to_dir = std::string (tmpdir);
5328 /* switch session directory temporarily */
5329 (*_session_dir) = to_dir;
5331 if (!_session_dir->create()) {
5332 (*_session_dir) = old_sd;
5333 remove_directory (to_dir);
5337 /* prepare archive */
5338 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5340 PBD::ScopedConnectionList progress_connection;
5341 PBD::FileArchive ar (archive);
5343 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5346 /* collect files to archive */
5347 std::map<string,string> filemap;
5349 vector<string> do_not_copy_extensions;
5350 do_not_copy_extensions.push_back (statefile_suffix);
5351 do_not_copy_extensions.push_back (pending_suffix);
5352 do_not_copy_extensions.push_back (backup_suffix);
5353 do_not_copy_extensions.push_back (temp_suffix);
5354 do_not_copy_extensions.push_back (history_suffix);
5356 vector<string> blacklist_dirs;
5357 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5358 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5359 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5360 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5361 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5362 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5364 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5365 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5366 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5368 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5369 if (only_used_sources) {
5370 playlists->sync_all_regions_with_regions ();
5371 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5374 /* collect audio sources for this session, calc total size for encoding
5375 * add option to only include *used* sources (see Session::cleanup_sources)
5377 size_t total_size = 0;
5379 Glib::Threads::Mutex::Lock lm (source_lock);
5381 /* build a list of used names */
5382 std::set<std::string> audio_file_names;
5383 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5384 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5385 if (!afs || afs->readable_length () == 0) {
5388 if (only_used_sources) {
5392 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5396 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5399 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5400 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5401 if (!afs || afs->readable_length () == 0) {
5405 if (only_used_sources) {
5409 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5414 std::string from = afs->path();
5416 if (compress_audio != NO_ENCODE) {
5417 total_size += afs->readable_length ();
5419 /* copy files as-is */
5420 if (!afs->within_session()) {
5421 string to = Glib::path_get_basename (from);
5423 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5424 * - avoid conflict with files existing in interchange
5425 * - avoid conflict with other embedded sources
5427 if (audio_file_names.find (to) == audio_file_names.end ()) {
5428 // we need a new name, add a '-<num>' before the '.<ext>'
5429 string bn = to.substr (0, to.find_last_of ('.'));
5430 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5431 to = bn + "-1" + ext;
5433 while (audio_file_names.find (to) == audio_file_names.end ()) {
5434 to = bump_name_once (to, '-');
5437 audio_file_names.insert (to);
5438 filemap[from] = make_new_audio_path (to, name, name);
5440 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5442 orig_origin[afs] = afs->origin ();
5443 afs->set_origin ("");
5446 filemap[from] = make_new_media_path (from, name, name);
5453 if (compress_audio != NO_ENCODE) {
5455 progress->set_progress (2); // set to "encoding"
5456 progress->set_progress (0);
5459 Glib::Threads::Mutex::Lock lm (source_lock);
5460 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5461 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5462 if (!afs || afs->readable_length () == 0) {
5466 if (only_used_sources) {
5470 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5475 orig_sources[afs] = afs->path();
5476 orig_gain[afs] = afs->gain();
5478 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5480 std::string channelsuffix = "";
5481 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5482 /* embedded external multi-channel files are converted to multiple-mono */
5483 channelsuffix = string_compose ("-c%1", afs->channel ());
5485 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5486 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5488 /* avoid name collisions of external files with same name */
5489 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5490 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5492 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5493 new_path = bump_name_once (new_path, '-');
5497 progress->descend ((float)afs->readable_length () / total_size);
5501 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5502 afs->replace_file (new_path);
5503 afs->set_gain (ns->gain(), true);
5506 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5510 progress->ascend ();
5516 progress->set_progress (-1); // set to "archiving"
5517 progress->set_progress (0);
5520 /* index files relevant for this session */
5521 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5522 vector<string> files;
5524 size_t prefix_len = (*sd).path.size();
5525 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5529 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5531 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5532 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5533 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5535 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5536 std::string from = *i;
5539 string filename = Glib::path_get_basename (from);
5540 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5541 if (filename == ".DS_STORE") {
5546 if (from.find (audiofile_dir_string) != string::npos) {
5548 } else if (from.find (midifile_dir_string) != string::npos) {
5549 filemap[from] = make_new_media_path (from, name, name);
5550 } else if (from.find (videofile_dir_string) != string::npos) {
5551 filemap[from] = make_new_media_path (from, name, name);
5553 bool do_copy = true;
5554 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5555 if (from.find (*v) != string::npos) {
5560 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5561 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5568 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5574 /* write session file */
5576 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5578 save_state (name, false, false, false, true, only_used_sources);
5580 save_default_options ();
5582 size_t prefix_len = _path.size();
5583 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5587 /* collect session-state files */
5588 vector<string> files;
5589 do_not_copy_extensions.clear ();
5590 do_not_copy_extensions.push_back (history_suffix);
5592 blacklist_dirs.clear ();
5593 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5595 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5596 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5597 std::string from = *i;
5598 bool do_copy = true;
5599 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5600 if (from.find (*v) != string::npos) {
5605 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5606 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5612 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5616 /* restore original values */
5619 set_snapshot_name (old_snapshot);
5620 (*_session_dir) = old_sd;
5621 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5622 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5624 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5625 i->first->set_origin (i->second);
5627 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5628 i->first->replace_file (i->second);
5630 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5631 i->first->set_gain (i->second, true);
5634 int rv = ar.create (filemap, compression_level);
5635 remove_directory (to_dir);
5641 Session::undo (uint32_t n)
5643 if (actively_recording()) {
5651 Session::redo (uint32_t n)
5653 if (actively_recording()) {