2 * Copyright (C) 1999-2019 Paul Davis <paul@linuxaudiosystems.com>
3 * Copyright (C) 2005-2006 Taybin Rutkin <taybin@taybin.com>
4 * Copyright (C) 2006-2014 David Robillard <d@drobilla.net>
5 * Copyright (C) 2006-2016 Tim Mayberry <mojofunk@gmail.com>
6 * Copyright (C) 2006 Jesse Chappell <jesse@essej.net>
7 * Copyright (C) 2007-2012 Carl Hetherington <carl@carlh.net>
8 * Copyright (C) 2008-2009 Hans Baier <hansfbaier@googlemail.com>
9 * Copyright (C) 2012-2019 Robin Gareus <robin@gareus.org>
10 * Copyright (C) 2013-2016 John Emmas <john@creativepost.co.uk>
11 * Copyright (C) 2013-2017 Nick Mainsbridge <mainsbridge@gmail.com>
12 * Copyright (C) 2014-2018 Ben Loftis <ben@harrisonconsoles.com>
13 * Copyright (C) 2017 Johannes Mueller <github@johannes-mueller.org>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 #include "libardour-config.h"
40 #include <cstdio> /* snprintf(3) ... grrr */
52 #if defined(__APPLE__) || defined(__FreeBSD__)
53 #include <sys/param.h>
54 #include <sys/mount.h>
57 #ifdef HAVE_SYS_STATVFS_H
58 #include <sys/statvfs.h>
62 #include "pbd/gstdio_compat.h"
63 #include "pbd/locale_guard.h"
66 #include <glibmm/threads.h>
67 #include <glibmm/fileutils.h>
69 #include <boost/algorithm/string.hpp>
71 #include "midi++/mmc.h"
72 #include "midi++/port.h"
74 #include "evoral/SMF.h"
76 #include "pbd/basename.h"
77 #include "pbd/debug.h"
78 #include "pbd/enumwriter.h"
79 #include "pbd/error.h"
80 #include "pbd/file_utils.h"
81 #include "pbd/pathexpand.h"
82 #include "pbd/pthread_utils.h"
83 #include "pbd/stacktrace.h"
84 #include "pbd/types_convert.h"
85 #include "pbd/localtime_r.h"
86 #include "pbd/unwind.h"
88 #include "ardour/amp.h"
89 #include "ardour/async_midi_port.h"
90 #include "ardour/audio_track.h"
91 #include "ardour/audioengine.h"
92 #include "ardour/audiofilesource.h"
93 #include "ardour/audioregion.h"
94 #include "ardour/auditioner.h"
95 #include "ardour/automation_control.h"
96 #include "ardour/boost_debug.h"
97 #include "ardour/butler.h"
98 #include "ardour/control_protocol_manager.h"
99 #include "ardour/directory_names.h"
100 #include "ardour/disk_reader.h"
101 #include "ardour/filename_extensions.h"
102 #include "ardour/graph.h"
103 #include "ardour/location.h"
105 #include "ardour/lv2_plugin.h"
107 #include "ardour/midi_model.h"
108 #include "ardour/midi_patch_manager.h"
109 #include "ardour/midi_region.h"
110 #include "ardour/midi_scene_changer.h"
111 #include "ardour/midi_source.h"
112 #include "ardour/midi_track.h"
113 #include "ardour/pannable.h"
114 #include "ardour/playlist_factory.h"
115 #include "ardour/playlist_source.h"
116 #include "ardour/port.h"
117 #include "ardour/processor.h"
118 #include "ardour/progress.h"
119 #include "ardour/profile.h"
120 #include "ardour/proxy_controllable.h"
121 #include "ardour/recent_sessions.h"
122 #include "ardour/region_factory.h"
123 #include "ardour/revision.h"
124 #include "ardour/route_group.h"
125 #include "ardour/send.h"
126 #include "ardour/selection.h"
127 #include "ardour/session.h"
128 #include "ardour/session_directory.h"
129 #include "ardour/session_metadata.h"
130 #include "ardour/session_playlists.h"
131 #include "ardour/session_state_utils.h"
132 #include "ardour/silentfilesource.h"
133 #include "ardour/smf_source.h"
134 #include "ardour/sndfilesource.h"
135 #include "ardour/source_factory.h"
136 #include "ardour/speakers.h"
137 #include "ardour/template_utils.h"
138 #include "ardour/tempo.h"
139 #include "ardour/ticker.h"
140 #include "ardour/transport_master_manager.h"
141 #include "ardour/types_convert.h"
142 #include "ardour/user_bundle.h"
143 #include "ardour/vca.h"
144 #include "ardour/vca_manager.h"
146 #include "control_protocol/control_protocol.h"
148 #include "LuaBridge/LuaBridge.h"
150 #include "pbd/i18n.h"
154 using namespace ARDOUR;
157 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
160 Session::pre_engine_init (string fullpath)
162 if (fullpath.empty()) {
164 throw failed_constructor();
167 /* discover canonical fullpath */
169 _path = canonical_path(fullpath);
173 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
175 /* finish initialization that can't be done in a normal C++ constructor
179 timerclear (&last_mmc_step);
180 g_atomic_int_set (&processing_prohibited, 0);
181 g_atomic_int_set (&_record_status, Disabled);
182 g_atomic_int_set (&_playback_load, 100);
183 g_atomic_int_set (&_capture_load, 100);
185 _all_route_group->set_active (true, this);
187 if (config.get_use_video_sync()) {
188 waiting_for_sync_offset = true;
190 waiting_for_sync_offset = false;
193 last_rr_session_dir = session_dirs.begin();
195 set_history_depth (Config->get_history_depth());
197 /* default: assume simple stereo speaker configuration */
199 _speakers->setup_default_speakers (2);
201 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
202 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
203 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
204 add_controllable (_solo_cut_control);
206 /* These are all static "per-class" signals */
208 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
209 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
210 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
211 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
213 /* stop IO objects from doing stuff until we're ready for them */
215 Delivery::disable_panners ();
216 IO::disable_connecting ();
220 Session::post_engine_init ()
222 BootMessage (_("Set block size and sample rate"));
224 set_block_size (_engine.samples_per_cycle());
225 set_sample_rate (_engine.sample_rate());
227 BootMessage (_("Using configuration"));
229 _midi_ports = new MidiPortManager;
231 MIDISceneChanger* msc;
233 _scene_changer = msc = new MIDISceneChanger (*this);
234 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
235 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
237 boost::function<samplecnt_t(void)> timer_func (boost::bind (&Session::audible_sample, this, (bool*)(0)));
238 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
240 setup_midi_machine_control ();
242 if (_butler->start_thread()) {
243 error << _("Butler did not start") << endmsg;
247 if (start_midi_thread ()) {
248 error << _("MIDI I/O thread did not start") << endmsg;
252 setup_click_sounds (0);
253 setup_midi_control ();
255 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
256 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
259 /* tempo map requires sample rate knowledge */
262 _tempo_map = new TempoMap (_current_sample_rate);
263 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
264 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
265 } catch (std::exception const & e) {
266 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
269 error << _("Unknown exception during session setup") << endmsg;
274 /* MidiClock requires a tempo map */
277 midi_clock = new MidiClockTicker ();
278 midi_clock->set_session (this);
280 /* crossfades require sample rate knowledge */
282 SndFileSource::setup_standard_crossfades (*this, sample_rate());
283 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this, true));
284 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
286 DiskReader::allocate_working_buffers();
287 refresh_disk_space ();
289 /* we're finally ready to call set_state() ... all objects have
290 * been created, the engine is running.
295 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
296 error << _("Could not set session state from XML") << endmsg;
299 } catch (PBD::unknown_enumeration& e) {
300 error << _("Session state: ") << e.what() << endmsg;
304 // set_state() will call setup_raid_path(), but if it's a new session we need
305 // to call setup_raid_path() here.
306 setup_raid_path (_path);
311 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
312 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
314 Config->map_parameters (ff);
315 config.map_parameters (ft);
316 _butler->map_parameters ();
318 /* Configure all processors; now that the
319 * engine is running, ports are re-established,
320 * and IOChange are complete.
323 Glib::Threads::Mutex::Lock lx (AudioEngine::instance()->process_lock ());
324 ProcessorChangeBlocker pcb (this);
325 boost::shared_ptr<RouteList> r = routes.reader ();
326 for (RouteList::iterator i = r->begin(); i != r->end(); ++i) {
327 (*i)->configure_processors (0);
331 /* Reset all panners */
333 Delivery::reset_panners ();
335 /* this will cause the CPM to instantiate any protocols that are in use
336 * (or mandatory), which will pass it this Session, and then call
337 * set_state() on each instantiated protocol to match stored state.
340 ControlProtocolManager::instance().set_session (this);
342 /* This must be done after the ControlProtocolManager set_session above,
343 as it will set states for ports which the ControlProtocolManager creates.
346 // XXX set state of MIDI::Port's
347 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
349 /* And this must be done after the MIDI::Manager::set_port_states as
350 * it will try to make connections whose details are loaded by set_port_states.
355 /* Let control protocols know that we are now all connected, so they
356 * could start talking to surfaces if they want to.
359 ControlProtocolManager::instance().midi_connectivity_established ();
361 if (_is_new && !no_auto_connect()) {
362 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
363 auto_connect_master_bus ();
366 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave | Dirty));
368 /* update latencies */
370 initialize_latencies ();
372 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
373 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
374 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
376 if (synced_to_engine()) {
377 _engine.transport_stop ();
380 // send_full_time_code (0);
382 } catch (AudioEngine::PortRegistrationFailure& err) {
383 error << err.what() << endmsg;
385 } catch (std::exception const & e) {
386 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
389 error << _("Unknown exception during session setup") << endmsg;
393 BootMessage (_("Reset Remote Controls"));
395 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
396 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
400 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
401 MIDI::Name::MidiPatchManager::instance().load_midnams_in_thread ();
402 /* initial program change will be delivered later; see ::config_changed() */
404 _state_of_the_state = Clean;
406 Port::set_connecting_blocked (false);
408 DirtyChanged (); /* EMIT SIGNAL */
410 /* Now, finally, we can fill the playback buffers */
412 BootMessage (_("Filling playback buffers"));
414 boost::shared_ptr<RouteList> rl = routes.reader();
415 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
416 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
417 if (trk && !trk->is_private_route()) {
418 trk->seek (_transport_sample, true);
426 Session::session_loaded ()
430 _state_of_the_state = Clean;
432 DirtyChanged (); /* EMIT SIGNAL */
436 } else if (state_was_pending) {
438 state_was_pending = false;
441 /* Now, finally, we can fill the playback buffers */
443 BootMessage (_("Filling playback buffers"));
444 force_locate (_transport_sample, false);
448 Session::raid_path () const
450 Searchpath raid_search_path;
452 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
453 raid_search_path += (*i).path;
456 return raid_search_path.to_string ();
460 Session::setup_raid_path (string path)
469 session_dirs.clear ();
471 Searchpath search_path(path);
472 Searchpath sound_search_path;
473 Searchpath midi_search_path;
475 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
477 sp.blocks = 0; // not needed
478 session_dirs.push_back (sp);
480 SessionDirectory sdir(sp.path);
482 sound_search_path += sdir.sound_path ();
483 midi_search_path += sdir.midi_path ();
486 // reset the round-robin soundfile path thingie
487 last_rr_session_dir = session_dirs.begin();
491 Session::path_is_within_session (const std::string& path)
493 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
494 if (PBD::path_is_within (i->path, path)) {
502 Session::ensure_subdirs ()
506 dir = session_directory().peak_path();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = session_directory().sound_path();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
520 dir = session_directory().midi_path();
522 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
523 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
527 dir = session_directory().dead_path();
529 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
534 dir = session_directory().export_path();
536 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
537 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
541 if(Profile->get_mixbus()) {
542 dir = session_directory().backup_path();
544 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
545 error << string_compose(_("Session: cannot create session backup folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
550 dir = analysis_dir ();
552 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
553 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
557 dir = plugins_dir ();
559 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
560 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
564 dir = externals_dir ();
566 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
567 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
574 /** @param session_template directory containing session template, or empty.
575 * Caller must not hold process lock.
578 Session::create (const string& session_template, BusProfile const * bus_profile)
580 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
581 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
585 if (ensure_subdirs ()) {
589 _writable = exists_and_writable (_path);
591 if (!session_template.empty()) {
592 string in_path = session_template_dir_to_file (session_template);
594 FILE* in = g_fopen (in_path.c_str(), "rb");
597 /* no need to call legalize_for_path() since the string
598 * in session_template is already a legal path name
600 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
602 FILE* out = g_fopen (out_path.c_str(), "wb");
606 stringstream new_session;
609 size_t charsRead = fread (buf, sizeof(char), 1024, in);
612 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
617 if (charsRead == 0) {
620 new_session.write (buf, charsRead);
624 string file_contents = new_session.str();
625 size_t writeSize = file_contents.length();
626 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
627 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
635 /* Copy plugin state files from template to new session */
636 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
637 copy_recurse (template_plugins, plugins_dir ());
642 error << string_compose (_("Could not open %1 for writing session template"), out_path)
649 error << string_compose (_("Could not open session template %1 for reading"), in_path)
656 _state_of_the_state = Clean;
658 /* set up Master Out and Monitor Out if necessary */
662 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
663 if (bus_profile->master_out_channels) {
664 int rv = add_master_bus (count);
670 if (Config->get_use_monitor_bus())
671 add_monitor_section ();
679 Session::maybe_write_autosave()
681 if (dirty() && record_status() != Recording) {
682 save_state("", true);
687 Session::remove_pending_capture_state ()
689 std::string pending_state_file_path(_session_dir->root_path());
691 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
693 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) {
697 if (::g_unlink (pending_state_file_path.c_str()) != 0) {
698 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
699 pending_state_file_path, g_strerror (errno)) << endmsg;
703 cerr << "removed " << pending_state_file_path << endl;
708 /** Rename a state file.
709 * @param old_name Old snapshot name.
710 * @param new_name New snapshot name.
713 Session::rename_state (string old_name, string new_name)
715 if (old_name == _current_snapshot_name || old_name == _name) {
716 /* refuse to rename the current snapshot or the "main" one */
720 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
721 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
723 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
724 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
726 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
727 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
728 old_name, new_name, g_strerror(errno)) << endmsg;
732 /** Remove a state file.
733 * @param snapshot_name Snapshot name.
736 Session::remove_state (string snapshot_name)
738 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
739 // refuse to remove the current snapshot or the "main" one
743 std::string xml_path(_session_dir->root_path());
745 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
747 if (!create_backup_file (xml_path)) {
748 // don't remove it if a backup can't be made
749 // create_backup_file will log the error.
754 if (g_remove (xml_path.c_str()) != 0) {
755 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
756 xml_path, g_strerror (errno)) << endmsg;
759 StateSaved (snapshot_name); /* EMIT SIGNAL */
762 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
764 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only, bool for_archive, bool only_used_assets)
766 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
769 std::string xml_path(_session_dir->root_path());
771 /* prevent concurrent saves from different threads */
773 Glib::Threads::Mutex::Lock lm (save_state_lock);
774 Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK);
779 if (!_writable || cannot_save()) {
783 if (g_atomic_int_get(&_suspend_save)) {
787 _save_queued = false;
789 snapshot_t fork_state = NormalSave;
790 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) {
791 /* snapshot, close midi */
792 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
796 const int64_t save_start_time = g_get_monotonic_time();
799 /* tell sources we're saving first, in case they write out to a new file
800 * which should be saved with the state rather than the old one */
801 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
803 i->second->session_saved();
804 } catch (Evoral::SMF::FileError& e) {
805 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
809 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, for_archive);
811 SessionSaveUnderway (); /* EMIT SIGNAL */
813 bool mark_as_clean = true;
814 if (!snapshot_name.empty() && !switch_to_snapshot) {
815 mark_as_clean = false;
819 mark_as_clean = false;
820 tree.set_root (&get_template());
822 tree.set_root (&state (false, fork_state, only_used_assets));
825 if (snapshot_name.empty()) {
826 snapshot_name = _current_snapshot_name;
827 } else if (switch_to_snapshot) {
828 set_snapshot_name (snapshot_name);
831 assert (!snapshot_name.empty());
835 /* proper save: use statefile_suffix (.ardour in English) */
837 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
839 /* make a backup copy of the old file */
841 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
842 // create_backup_file will log the error
847 assert (snapshot_name == _current_snapshot_name);
848 /* pending save: use pending_suffix (.pending in English) */
849 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
852 std::string tmp_path(_session_dir->root_path());
853 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
856 cerr << "actually writing state to " << tmp_path << endl;
859 if (!tree.write (tmp_path)) {
860 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
861 if (g_remove (tmp_path.c_str()) != 0) {
862 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
863 tmp_path, g_strerror (errno)) << endmsg;
870 cerr << "renaming state to " << xml_path << endl;
873 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
874 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
875 tmp_path, xml_path, g_strerror(errno)) << endmsg;
876 if (g_remove (tmp_path.c_str()) != 0) {
877 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
878 tmp_path, g_strerror (errno)) << endmsg;
884 //Mixbus auto-backup mechanism
885 if(Profile->get_mixbus()) {
886 if (pending) { //"pending" save means it's a backup, or some other non-user-initiated save; a good time to make a backup
887 // make a serialized safety backup
888 // (will make one periodically but only one per hour is left on disk)
889 // these backup files go into a separated folder
892 struct tm local_time;
894 localtime_r (&n, &local_time);
895 strftime (timebuf, sizeof(timebuf), "%y-%m-%d.%H", &local_time);
896 std::string save_path(session_directory().backup_path());
897 save_path += G_DIR_SEPARATOR;
898 save_path += legalize_for_path(_current_snapshot_name);
900 save_path += timebuf;
901 save_path += statefile_suffix;
902 if ( !tree.write (save_path) )
903 error << string_compose(_("Could not save backup file at path \"%1\" (%2)"),
904 save_path, g_strerror (errno)) << endmsg;
907 StateSaved (snapshot_name); /* EMIT SIGNAL */
910 if (!pending && !for_archive) {
912 save_history (snapshot_name);
915 unset_dirty (/* EMIT SIGNAL */ true);
918 StateSaved (snapshot_name); /* EMIT SIGNAL */
922 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
923 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
926 if (!pending && !for_archive && ! template_only) {
927 remove_pending_capture_state ();
934 Session::restore_state (string snapshot_name)
937 if (load_state (snapshot_name) == 0) {
938 set_state (*state_tree->root(), Stateful::loading_state_version);
942 // unknown_enumeration
950 Session::load_state (string snapshot_name)
955 state_was_pending = false;
957 /* check for leftover pending state from a crashed capture attempt */
959 std::string xmlpath(_session_dir->root_path());
960 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
962 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
964 /* there is pending state from a crashed capture attempt */
966 boost::optional<int> r = AskAboutPendingState();
967 if (r.value_or (1)) {
968 state_was_pending = true;
972 if (!state_was_pending) {
973 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
976 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
977 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
978 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
979 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
984 state_tree = new XMLTree;
988 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
990 if (!state_tree->read (xmlpath)) {
991 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
997 XMLNode const & root (*state_tree->root());
999 if (root.name() != X_("Session")) {
1000 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
1006 std::string version;
1007 root.get_property ("version", version);
1008 Stateful::loading_state_version = parse_stateful_loading_version (version);
1010 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
1011 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
1012 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
1015 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1017 std::string backup_path(_session_dir->root_path());
1018 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1019 backup_path = Glib::build_filename (backup_path, backup_filename);
1021 // only create a backup for a given statefile version once
1023 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1025 VersionMismatch (xmlpath, backup_path);
1027 if (!copy_file (xmlpath, backup_path)) {;
1033 save_snapshot_name (snapshot_name);
1039 Session::load_options (const XMLNode& node)
1041 config.set_variables (node);
1046 Session::save_default_options ()
1048 return config.save_state();
1052 Session::get_state ()
1054 /* this is not directly called, but required by PBD::Stateful */
1056 return state (false, NormalSave);
1060 Session::get_template ()
1062 /* if we don't disable rec-enable, diskstreams
1063 will believe they need to store their capture
1064 sources in their state node.
1067 disable_record (false);
1069 return state (true, NormalSave);
1072 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1073 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1076 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1078 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1081 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1085 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1088 XMLNode* node = new XMLNode("TrackState"); // XXX
1091 PlaylistSet playlists; // SessionPlaylists
1094 // these will work with new_route_from_template()
1095 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1096 child = node->add_child ("Routes");
1097 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1098 if ((*i)->is_auditioner()) {
1101 if ((*i)->is_master() || (*i)->is_monitor()) {
1104 child->add_child_nocopy ((*i)->get_state());
1105 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1107 playlists.insert (track->playlist ());
1111 // on load, Regions in the playlists need to resolve and map Source-IDs
1112 // also playlist needs to be merged or created with new-name..
1113 // ... and Diskstream in tracks adjusted to use the correct playlist
1114 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1115 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1116 child->add_child_nocopy ((*i)->get_state ());
1117 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1118 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1119 const Region::SourceList& sl = (*s)->sources ();
1120 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1121 sources.insert (*sli);
1126 child = node->add_child ("Sources");
1127 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1128 child->add_child_nocopy ((*i)->get_state ());
1129 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1131 #ifdef PLATFORM_WINDOWS
1134 string p = fs->path ();
1135 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1139 std::string sn = Glib::build_filename (path, "share.axml");
1142 tree.set_root (node);
1143 return tree.write (sn.c_str());
1147 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
1149 pl->deep_sources (*all_sources);
1154 struct route_id_compare {
1156 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1158 return r1->id () < r2->id ();
1164 Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets)
1167 XMLNode* node = new XMLNode("Session");
1170 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1172 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1174 child = node->add_child ("ProgramVersion");
1175 child->set_property("created-with", created_with);
1177 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1178 child->set_property("modified-with", modified_with);
1180 /* store configuration settings */
1182 if (!save_template) {
1184 node->set_property ("name", _name);
1185 node->set_property ("sample-rate", _base_sample_rate);
1187 if (session_dirs.size() > 1) {
1191 vector<space_and_path>::iterator i = session_dirs.begin();
1192 vector<space_and_path>::iterator next;
1194 ++i; /* skip the first one */
1198 while (i != session_dirs.end()) {
1202 if (next != session_dirs.end()) {
1203 p += G_SEARCHPATH_SEPARATOR;
1212 child = node->add_child ("Path");
1213 child->add_content (p);
1215 node->set_property ("end-is-free", _session_range_is_free); //deprecated, but keep storing this value for compatibility with prior v5.
1216 node->set_property ("session-range-is-free", _session_range_is_free);
1219 /* save the ID counter */
1221 node->set_property ("id-counter", ID::counter());
1223 node->set_property ("name-counter", name_id_counter ());
1225 /* save the event ID counter */
1227 node->set_property ("event-counter", Evoral::event_id_counter());
1229 /* save the VCA counter */
1231 node->set_property ("vca-counter", VCA::get_next_vca_number());
1233 /* various options */
1235 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1236 if (!midi_port_nodes.empty()) {
1237 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1238 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1239 midi_port_stuff->add_child_nocopy (**n);
1241 node->add_child_nocopy (*midi_port_stuff);
1244 XMLNode& cfgxml (config.get_variables ());
1245 if (save_template) {
1246 /* exclude search-paths from template */
1247 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1248 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1249 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1251 node->add_child_nocopy (cfgxml);
1253 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1255 child = node->add_child ("Sources");
1257 if (!save_template) {
1258 Glib::Threads::Mutex::Lock sl (source_lock);
1260 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1262 if (only_used_assets) {
1263 _playlists->sync_all_regions_with_regions ();
1264 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1267 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1269 /* Don't save information about non-file Sources, or
1270 * about non-destructive file sources that are empty
1271 * and unused by any regions.
1273 boost::shared_ptr<FileSource> fs;
1275 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1279 if (!fs->destructive()) {
1280 if (fs->empty() && !fs->used()) {
1285 if (only_used_assets) {
1286 /* skip only unused audio files */
1287 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1288 if (afs && !afs->used()) {
1291 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1296 if (snapshot_type != NormalSave && fs->within_session ()) {
1297 /* copy MIDI sources to new file
1299 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1300 * because the GUI (midi_region) has a direct pointer to the midi-model
1301 * of the source, as does UndoTransaction.
1303 * On the upside, .mid files are not kept open. The file is only open
1304 * when reading the model initially and when flushing the model to disk:
1305 * source->session_saved () or export.
1307 * We can change the _path of the existing source under the hood, keeping
1308 * all IDs, references and pointers intact.
1310 boost::shared_ptr<SMFSource> ms;
1311 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1312 const std::string ancestor_name = ms->ancestor_name();
1313 const std::string base = PBD::basename_nosuffix(ancestor_name);
1314 const string path = new_midi_source_path (base, false);
1316 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1317 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1318 Source::Lock lm (ms->mutex());
1320 // TODO special-case empty, removable() files: just create a new removable.
1321 // (load + write flushes the model and creates the file)
1323 ms->load_model (lm);
1325 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1326 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1328 if (snapshot_type == SnapshotKeep) {
1329 /* keep working on current session.
1331 * Save snapshot-state with the original filename.
1332 * Switch to use new path for future saves of the main session.
1334 child->add_child_nocopy (ms->get_state());
1338 * ~SMFSource unlinks removable() files.
1340 std::string npath (ms->path ());
1341 ms->replace_file (newsrc->path ());
1342 newsrc->replace_file (npath);
1344 if (snapshot_type == SwitchToSnapshot) {
1345 /* save and switch to snapshot.
1347 * Leave the old file in place (as is).
1348 * Snapshot uses new source directly
1350 child->add_child_nocopy (ms->get_state());
1357 child->add_child_nocopy (siter->second->get_state());
1361 child = node->add_child ("Regions");
1363 if (!save_template) {
1364 Glib::Threads::Mutex::Lock rl (region_lock);
1366 if (!only_used_assets) {
1367 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1368 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1369 boost::shared_ptr<Region> r = i->second;
1370 /* only store regions not attached to playlists */
1371 if (r->playlist() == 0) {
1372 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1373 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1375 child->add_child_nocopy (r->get_state ());
1381 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1383 if (!cassocs.empty()) {
1384 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1386 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1387 if (i->first->playlist () == 0 && only_used_assets) {
1390 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1391 can->set_property (X_("copy"), i->first->id());
1392 can->set_property (X_("original"), i->second->id());
1393 ca->add_child_nocopy (*can);
1394 /* see above, child is still "Regions" here */
1395 if (i->second->playlist() == 0 && only_used_assets) {
1396 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1397 child->add_child_nocopy (ar->get_basic_state ());
1399 child->add_child_nocopy (ar->get_state ());
1406 if (!save_template) {
1408 node->add_child_nocopy (_selection->get_state());
1411 node->add_child_nocopy (_locations->get_state());
1414 Locations loc (*this);
1415 const bool was_dirty = dirty();
1416 // for a template, just create a new Locations, populate it
1417 // with the default start and end, and get the state for that.
1418 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1419 range->set (max_samplepos, 0);
1421 XMLNode& locations_state = loc.get_state();
1423 node->add_child_nocopy (locations_state);
1425 /* adding a location above will have marked the session
1426 * dirty. This is an artifact, so fix it if the session wasn't
1435 child = node->add_child ("Bundles");
1437 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1438 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1439 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1441 child->add_child_nocopy (b->get_state());
1446 node->add_child_nocopy (_vca_manager->get_state());
1448 child = node->add_child ("Routes");
1450 boost::shared_ptr<RouteList> r = routes.reader ();
1452 route_id_compare cmp;
1453 RouteList xml_node_order (*r);
1454 xml_node_order.sort (cmp);
1456 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1457 if (!(*i)->is_auditioner()) {
1458 if (save_template) {
1459 child->add_child_nocopy ((*i)->get_template());
1461 child->add_child_nocopy ((*i)->get_state());
1467 _playlists->add_state (node, save_template, !only_used_assets);
1469 child = node->add_child ("RouteGroups");
1470 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1471 child->add_child_nocopy ((*i)->get_state());
1475 XMLNode* gain_child = node->add_child ("Click");
1476 gain_child->add_child_nocopy (_click_io->get_state ());
1477 gain_child->add_child_nocopy (_click_gain->get_state ());
1481 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1482 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1485 node->add_child_nocopy (_speakers->get_state());
1486 node->add_child_nocopy (_tempo_map->get_state());
1487 node->add_child_nocopy (get_control_protocol_state());
1490 node->add_child_copy (*_extra_xml);
1494 Glib::Threads::Mutex::Lock lm (lua_lock);
1497 luabridge::LuaRef savedstate ((*_lua_save)());
1498 saved = savedstate.cast<std::string>();
1500 lua.collect_garbage ();
1503 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1504 std::string b64s (b64);
1507 XMLNode* script_node = new XMLNode (X_("Script"));
1508 script_node->set_property (X_("lua"), LUA_VERSION);
1509 script_node->add_content (b64s);
1510 node->add_child_nocopy (*script_node);
1517 Session::get_control_protocol_state ()
1519 return ControlProtocolManager::instance().get_state ();
1523 Session::set_state (const XMLNode& node, int version)
1530 _state_of_the_state = StateOfTheState (_state_of_the_state | CannotSave);
1532 if (node.name() != X_("Session")) {
1533 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1537 node.get_property ("name", _name);
1539 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1541 _nominal_sample_rate = _base_sample_rate;
1543 assert (AudioEngine::instance()->running ());
1544 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1545 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1546 if (r.value_or (0)) {
1552 created_with = "unknown";
1553 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1554 child->get_property (X_("created-with"), created_with);
1557 setup_raid_path(_session_dir->root_path());
1559 node.get_property (X_("end-is-free"), _session_range_is_free); //deprectated, but use old values if they are in the config
1561 node.get_property (X_("session-range-is-free"), _session_range_is_free);
1564 if (node.get_property (X_("id-counter"), counter)) {
1565 ID::init_counter (counter);
1567 /* old sessions used a timebased counter, so fake
1568 * the startup ID counter based on a standard
1573 ID::init_counter (now);
1576 if (node.get_property (X_("name-counter"), counter)) {
1577 init_name_id_counter (counter);
1580 if (node.get_property (X_("event-counter"), counter)) {
1581 Evoral::init_event_id_counter (counter);
1584 if (node.get_property (X_("vca-counter"), counter)) {
1585 VCA::set_next_vca_number (counter);
1587 VCA::set_next_vca_number (1);
1590 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1591 _midi_ports->set_midi_port_states (child->children());
1594 IO::disable_connecting ();
1596 Stateful::save_extra_xml (node);
1598 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1599 load_options (*child);
1600 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1601 load_options (*child);
1603 error << _("Session: XML state has no options section") << endmsg;
1606 if (version >= 3000) {
1607 if ((child = find_named_node (node, "Metadata")) == 0) {
1608 warning << _("Session: XML state has no metadata section") << endmsg;
1609 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1614 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1615 _speakers->set_state (*child, version);
1618 if ((child = find_named_node (node, "Sources")) == 0) {
1619 error << _("Session: XML state has no sources section") << endmsg;
1621 } else if (load_sources (*child)) {
1625 if ((child = find_named_node (node, "TempoMap")) == 0) {
1626 error << _("Session: XML state has no Tempo Map section") << endmsg;
1628 } else if (_tempo_map->set_state (*child, version)) {
1632 if ((child = find_named_node (node, "Locations")) == 0) {
1633 error << _("Session: XML state has no locations section") << endmsg;
1635 } else if (_locations->set_state (*child, version)) {
1639 locations_changed ();
1641 if (_session_range_location) {
1642 AudioFileSource::set_header_position_offset (_session_range_location->start());
1645 if ((child = find_named_node (node, "Regions")) == 0) {
1646 error << _("Session: XML state has no Regions section") << endmsg;
1648 } else if (load_regions (*child)) {
1652 if ((child = find_named_node (node, "Playlists")) == 0) {
1653 error << _("Session: XML state has no playlists section") << endmsg;
1655 } else if (_playlists->load (*this, *child)) {
1659 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1661 } else if (_playlists->load_unused (*this, *child)) {
1665 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1666 if (load_compounds (*child)) {
1671 if (version >= 3000) {
1672 if ((child = find_named_node (node, "Bundles")) == 0) {
1673 warning << _("Session: XML state has no bundles section") << endmsg;
1676 /* We can't load Bundles yet as they need to be able
1677 * to convert from port names to Port objects, which can't happen until
1679 _bundle_xml_node = new XMLNode (*child);
1683 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1684 _vca_manager->set_state (*child, version);
1687 if (version < 3000) {
1688 if ((child = find_named_node (node, "DiskStreams"))) {
1689 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1690 if ((*n)->name() == "AudioDiskstream" || (*n)->name() == "DiskStream") {
1691 std::string diskstream_id;
1692 std::string playlist_name;
1693 if ((*n)->get_property ("playlist", playlist_name) && (*n)->get_property ("id", diskstream_id)) {
1694 _diskstreams_2X [PBD::ID(diskstream_id)] = playlist_name;
1701 if ((child = find_named_node (node, "Routes")) == 0) {
1702 error << _("Session: XML state has no routes section") << endmsg;
1704 } else if (load_routes (*child, version)) {
1708 /* Now that we Tracks have been loaded and playlists are assigned */
1709 _playlists->update_tracking ();
1711 _diskstreams_2X.clear ();
1713 /* Now that we have Routes and masters loaded, connect them if appropriate */
1715 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1717 if (version >= 3000) {
1719 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1720 error << _("Session: XML state has no route groups section") << endmsg;
1722 } else if (load_route_groups (*child, version)) {
1726 } else if (version < 3000) {
1728 if ((child = find_named_node (node, "EditGroups")) == 0) {
1729 error << _("Session: XML state has no edit groups section") << endmsg;
1731 } else if (load_route_groups (*child, version)) {
1735 if ((child = find_named_node (node, "MixGroups")) == 0) {
1736 error << _("Session: XML state has no mix groups section") << endmsg;
1738 } else if (load_route_groups (*child, version)) {
1743 if ((child = find_named_node (node, "Click")) == 0) {
1744 warning << _("Session: XML state has no click section") << endmsg;
1745 } else if (_click_io) {
1746 setup_click_state (&node);
1749 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1750 ControlProtocolManager::instance().set_state (*child, 1 /* here: session-specific state */);
1753 if ((child = find_named_node (node, "Script"))) {
1754 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1755 if (!(*n)->is_content ()) { continue; }
1757 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1759 Glib::Threads::Mutex::Lock lm (lua_lock);
1760 (*_lua_load)(std::string ((const char*)buf, size));
1761 } catch (luabridge::LuaException const& e) {
1762 cerr << "LuaException:" << e.what () << endl;
1768 if ((child = find_named_node (node, X_("Selection")))) {
1769 _selection->set_state (*child, version);
1772 update_route_record_state ();
1774 /* here beginneth the second phase ... */
1775 set_snapshot_name (_current_snapshot_name);
1777 StateReady (); /* EMIT SIGNAL */
1790 Session::load_routes (const XMLNode& node, int version)
1793 XMLNodeConstIterator niter;
1794 RouteList new_routes;
1796 nlist = node.children();
1800 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1802 boost::shared_ptr<Route> route;
1804 if (version < 3000) {
1805 route = XMLRouteFactory_2X (**niter, version);
1806 } else if (version < 5000) {
1807 route = XMLRouteFactory_3X (**niter, version);
1809 route = XMLRouteFactory (**niter, version);
1813 error << _("Session: cannot create Route from XML description.") << endmsg;
1817 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1819 new_routes.push_back (route);
1822 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1824 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1826 BootMessage (_("Finished adding tracks/busses"));
1831 boost::shared_ptr<Route>
1832 Session::XMLRouteFactory (const XMLNode& node, int version)
1834 boost::shared_ptr<Route> ret;
1836 if (node.name() != "Route") {
1840 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1843 pl_prop = node.property (X_("midi-playlist"));
1846 DataType type = DataType::AUDIO;
1847 node.get_property("default-type", type);
1849 assert (type != DataType::NIL);
1853 /* has at least 1 playlist, therefore a track ... */
1855 boost::shared_ptr<Track> track;
1857 if (type == DataType::AUDIO) {
1858 track.reset (new AudioTrack (*this, string())); // name will be reset from XML in ::set_state() below
1860 track.reset (new MidiTrack (*this, string())); // name will be reset from XML in ::set_state() below
1863 if (track->init()) {
1867 if (track->set_state (node, version)) {
1871 BOOST_MARK_TRACK (track);
1875 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1876 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1879 if (r->init () == 0 && r->set_state (node, version) == 0) {
1880 BOOST_MARK_ROUTE (r);
1888 boost::shared_ptr<Route>
1889 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1891 boost::shared_ptr<Route> ret;
1893 if (node.name() != "Route") {
1897 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1899 DataType type = DataType::AUDIO;
1900 node.get_property("default-type", type);
1902 assert (type != DataType::NIL);
1906 boost::shared_ptr<Track> track;
1908 if (type == DataType::AUDIO) {
1909 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1911 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1914 if (track->init()) {
1918 if (track->set_state (node, version)) {
1922 BOOST_MARK_TRACK (track);
1926 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1927 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1929 if (r->init () == 0 && r->set_state (node, version) == 0) {
1930 BOOST_MARK_ROUTE (r);
1938 boost::shared_ptr<Route>
1939 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1941 boost::shared_ptr<Route> ret;
1943 if (node.name() != "Route") {
1947 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1949 ds_prop = node.property (X_("diskstream"));
1952 DataType type = DataType::AUDIO;
1953 node.get_property("default-type", type);
1955 assert (type != DataType::NIL);
1959 PBD::ID ds_id (ds_prop->value ());
1960 std::string playlist_name = _diskstreams_2X[ds_id];
1962 boost::shared_ptr<Playlist> pl = playlists()->by_name (playlist_name);
1964 if (playlist_name.empty () || !pl) {
1965 warning << string_compose (_("Could not find diskstream for diskream-id: '%1', playlist: '%2'"), ds_prop->value (), playlist_name) << endmsg;
1968 boost::shared_ptr<Track> track;
1970 if (type == DataType::AUDIO) {
1971 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1973 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1976 if (track->init()) {
1981 track->use_playlist (DataType::AUDIO, pl);
1984 if (track->set_state (node, version)) {
1989 pl->set_orig_track_id (track->id());
1990 playlists()->update_orig_2X (ds_id, track->id());
1993 BOOST_MARK_TRACK (track);
1997 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1998 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
2000 if (r->init () == 0 && r->set_state (node, version) == 0) {
2001 BOOST_MARK_ROUTE (r);
2010 Session::load_regions (const XMLNode& node)
2013 XMLNodeConstIterator niter;
2014 boost::shared_ptr<Region> region;
2016 nlist = node.children();
2020 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2021 if ((region = XMLRegionFactory (**niter, false)) == 0) {
2022 error << _("Session: cannot create Region from XML description.");
2023 XMLProperty const * name = (**niter).property("name");
2026 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
2037 Session::load_compounds (const XMLNode& node)
2039 XMLNodeList calist = node.children();
2040 XMLNodeConstIterator caiter;
2041 XMLProperty const * caprop;
2043 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
2044 XMLNode* ca = *caiter;
2048 if ((caprop = ca->property (X_("original"))) == 0) {
2051 orig_id = caprop->value();
2053 if ((caprop = ca->property (X_("copy"))) == 0) {
2056 copy_id = caprop->value();
2058 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2059 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2061 if (!orig || !copy) {
2062 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2068 RegionFactory::add_compound_association (orig, copy);
2075 Session::load_nested_sources (const XMLNode& node)
2078 XMLNodeConstIterator niter;
2080 nlist = node.children();
2082 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2083 if ((*niter)->name() == "Source") {
2085 /* it may already exist, so don't recreate it unnecessarily
2088 XMLProperty const * prop = (*niter)->property (X_("id"));
2090 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2094 ID source_id (prop->value());
2096 if (!source_by_id (source_id)) {
2099 SourceFactory::create (*this, **niter, true);
2101 catch (failed_constructor& err) {
2102 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2109 boost::shared_ptr<Region>
2110 Session::XMLRegionFactory (const XMLNode& node, bool full)
2112 XMLProperty const * type = node.property("type");
2116 const XMLNodeList& nlist = node.children();
2118 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2119 XMLNode *child = (*niter);
2120 if (child->name() == "NestedSource") {
2121 load_nested_sources (*child);
2125 if (!type || type->value() == "audio") {
2126 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2127 } else if (type->value() == "midi") {
2128 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2131 } catch (failed_constructor& err) {
2132 return boost::shared_ptr<Region> ();
2135 return boost::shared_ptr<Region> ();
2138 boost::shared_ptr<AudioRegion>
2139 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2141 XMLProperty const * prop;
2142 boost::shared_ptr<Source> source;
2143 boost::shared_ptr<AudioSource> as;
2145 SourceList master_sources;
2146 uint32_t nchans = 1;
2149 if (node.name() != X_("Region")) {
2150 return boost::shared_ptr<AudioRegion>();
2153 node.get_property (X_("channels"), nchans);
2155 if ((prop = node.property ("name")) == 0) {
2156 cerr << "no name for this region\n";
2160 if ((prop = node.property (X_("source-0"))) == 0) {
2161 if ((prop = node.property ("source")) == 0) {
2162 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2163 return boost::shared_ptr<AudioRegion>();
2167 PBD::ID s_id (prop->value());
2169 if ((source = source_by_id (s_id)) == 0) {
2170 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2171 return boost::shared_ptr<AudioRegion>();
2174 as = boost::dynamic_pointer_cast<AudioSource>(source);
2176 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2177 return boost::shared_ptr<AudioRegion>();
2180 sources.push_back (as);
2182 /* pickup other channels */
2184 for (uint32_t n=1; n < nchans; ++n) {
2185 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2186 if ((prop = node.property (buf)) != 0) {
2188 PBD::ID id2 (prop->value());
2190 if ((source = source_by_id (id2)) == 0) {
2191 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2192 return boost::shared_ptr<AudioRegion>();
2195 as = boost::dynamic_pointer_cast<AudioSource>(source);
2197 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2198 return boost::shared_ptr<AudioRegion>();
2200 sources.push_back (as);
2204 for (uint32_t n = 0; n < nchans; ++n) {
2205 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2206 if ((prop = node.property (buf)) != 0) {
2208 PBD::ID id2 (prop->value());
2210 if ((source = source_by_id (id2)) == 0) {
2211 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2212 return boost::shared_ptr<AudioRegion>();
2215 as = boost::dynamic_pointer_cast<AudioSource>(source);
2217 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2218 return boost::shared_ptr<AudioRegion>();
2220 master_sources.push_back (as);
2225 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2227 /* a final detail: this is the one and only place that we know how long missing files are */
2229 if (region->whole_file()) {
2230 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2231 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2233 sfp->set_length (region->length());
2238 if (!master_sources.empty()) {
2239 if (master_sources.size() != nchans) {
2240 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2242 region->set_master_sources (master_sources);
2250 catch (failed_constructor& err) {
2251 return boost::shared_ptr<AudioRegion>();
2255 boost::shared_ptr<MidiRegion>
2256 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2258 XMLProperty const * prop;
2259 boost::shared_ptr<Source> source;
2260 boost::shared_ptr<MidiSource> ms;
2263 if (node.name() != X_("Region")) {
2264 return boost::shared_ptr<MidiRegion>();
2267 if ((prop = node.property ("name")) == 0) {
2268 cerr << "no name for this region\n";
2272 if ((prop = node.property (X_("source-0"))) == 0) {
2273 if ((prop = node.property ("source")) == 0) {
2274 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2275 return boost::shared_ptr<MidiRegion>();
2279 PBD::ID s_id (prop->value());
2281 if ((source = source_by_id (s_id)) == 0) {
2282 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2283 return boost::shared_ptr<MidiRegion>();
2286 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2288 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2289 return boost::shared_ptr<MidiRegion>();
2292 sources.push_back (ms);
2295 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2296 /* a final detail: this is the one and only place that we know how long missing files are */
2298 if (region->whole_file()) {
2299 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2300 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2302 sfp->set_length (region->length());
2310 catch (failed_constructor& err) {
2311 return boost::shared_ptr<MidiRegion>();
2316 Session::get_sources_as_xml ()
2319 XMLNode* node = new XMLNode (X_("Sources"));
2320 Glib::Threads::Mutex::Lock lm (source_lock);
2322 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2323 node->add_child_nocopy (i->second->get_state());
2330 Session::reset_write_sources (bool mark_write_complete, bool force)
2332 boost::shared_ptr<RouteList> rl = routes.reader();
2333 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2334 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2336 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
2337 tr->reset_write_sources(mark_write_complete, force);
2338 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2344 Session::load_sources (const XMLNode& node)
2347 XMLNodeConstIterator niter;
2348 /* don't need this but it stops some
2349 * versions of gcc complaining about
2350 * discarded return values.
2352 boost::shared_ptr<Source> source;
2354 nlist = node.children();
2357 std::map<std::string, std::string> relocation;
2359 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2360 #ifdef PLATFORM_WINDOWS
2364 XMLNode srcnode (**niter);
2365 bool try_replace_abspath = true;
2369 #ifdef PLATFORM_WINDOWS
2370 // do not show "insert media" popups (files embedded from removable media).
2371 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2373 if ((source = XMLSourceFactory (srcnode)) == 0) {
2374 error << _("Session: cannot create Source from XML description.") << endmsg;
2376 #ifdef PLATFORM_WINDOWS
2377 SetErrorMode(old_mode);
2380 } catch (MissingSource& err) {
2381 #ifdef PLATFORM_WINDOWS
2382 SetErrorMode(old_mode);
2385 /* try previous abs path replacements first */
2386 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2387 std::string dir = Glib::path_get_dirname (err.path);
2388 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2389 if (rl != relocation.end ()) {
2390 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2391 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2392 srcnode.set_property ("origin", newpath);
2393 try_replace_abspath = false;
2400 _missing_file_replacement = "";
2402 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2403 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2404 PROGRAM_NAME) << endmsg;
2408 if (!no_questions_about_missing_files) {
2409 user_choice = MissingFile (this, err.path, err.type).value_or (-1);
2414 switch (user_choice) {
2416 /* user added a new search location
2417 * or selected a new absolute path,
2419 if (Glib::path_is_absolute (err.path)) {
2420 if (!_missing_file_replacement.empty ()) {
2421 /* replace origin, in XML */
2422 std::string newpath = Glib::build_filename (
2423 _missing_file_replacement, Glib::path_get_basename (err.path));
2424 srcnode.set_property ("origin", newpath);
2425 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2426 _missing_file_replacement = "";
2433 /* user asked to quit the entire session load */
2437 no_questions_about_missing_files = true;
2441 no_questions_about_missing_files = true;
2448 case DataType::AUDIO:
2449 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2452 case DataType::MIDI:
2453 /* The MIDI file is actually missing so
2454 * just create a new one in the same
2455 * location. Do not announce its
2459 if (!Glib::path_is_absolute (err.path)) {
2460 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2462 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2467 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2468 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2469 /* reset ID to match the missing one */
2470 source->set_id (**niter);
2471 /* Now we can announce it */
2472 SourceFactory::SourceCreated (source);
2483 boost::shared_ptr<Source>
2484 Session::XMLSourceFactory (const XMLNode& node)
2486 if (node.name() != "Source") {
2487 return boost::shared_ptr<Source>();
2491 /* note: do peak building in another thread when loading session state */
2492 return SourceFactory::create (*this, node, true);
2495 catch (failed_constructor& err) {
2496 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2497 return boost::shared_ptr<Source>();
2502 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2504 if (cannot_save () || template_name.empty ()) {
2508 bool absolute_path = Glib::path_is_absolute (template_name);
2510 /* directory to put the template in */
2511 std::string template_dir_path;
2513 if (!absolute_path) {
2514 std::string user_template_dir(user_template_directory());
2516 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2517 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2518 user_template_dir, g_strerror (errno)) << endmsg;
2522 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2524 template_dir_path = template_name;
2527 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2528 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2529 template_dir_path) << endmsg;
2533 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2534 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2535 template_dir_path, g_strerror (errno)) << endmsg;
2540 std::string template_file_path;
2542 if (absolute_path) {
2543 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2545 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2548 SessionSaveUnderway (); /* EMIT SIGNAL */
2553 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2554 root = &get_template ();
2557 root->remove_nodes_and_delete (X_("description"));
2559 if (!description.empty()) {
2560 XMLNode* desc = new XMLNode (X_("description"));
2561 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2562 desc->add_child_nocopy (*desc_cont);
2564 root->add_child_nocopy (*desc);
2567 tree.set_root (root);
2569 if (!tree.write (template_file_path)) {
2570 error << _("template not saved") << endmsg;
2574 store_recent_templates (template_file_path);
2580 Session::refresh_disk_space ()
2582 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2584 Glib::Threads::Mutex::Lock lm (space_lock);
2586 /* get freespace on every FS that is part of the session path */
2588 _total_free_4k_blocks = 0;
2589 _total_free_4k_blocks_uncertain = false;
2591 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2592 #if defined(__NetBSD__)
2593 struct statvfs statfsbuf;
2595 statvfs (i->path.c_str(), &statfsbuf);
2597 struct statfs statfsbuf;
2599 statfs (i->path.c_str(), &statfsbuf);
2601 double const scale = statfsbuf.f_bsize / 4096.0;
2603 /* See if this filesystem is read-only */
2604 struct statvfs statvfsbuf;
2605 statvfs (i->path.c_str(), &statvfsbuf);
2607 /* f_bavail can be 0 if it is undefined for whatever
2608 filesystem we are looking at; Samba shares mounted
2609 via GVFS are an example of this.
2611 if (statfsbuf.f_bavail == 0) {
2612 /* block count unknown */
2614 i->blocks_unknown = true;
2615 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2616 /* read-only filesystem */
2618 i->blocks_unknown = false;
2620 /* read/write filesystem with known space */
2621 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2622 i->blocks_unknown = false;
2625 _total_free_4k_blocks += i->blocks;
2626 if (i->blocks_unknown) {
2627 _total_free_4k_blocks_uncertain = true;
2630 #elif defined PLATFORM_WINDOWS
2631 vector<string> scanned_volumes;
2632 vector<string>::iterator j;
2633 vector<space_and_path>::iterator i;
2634 DWORD nSectorsPerCluster, nBytesPerSector,
2635 nFreeClusters, nTotalClusters;
2639 _total_free_4k_blocks = 0;
2641 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2642 strncpy (disk_drive, (*i).path.c_str(), 3);
2646 volume_found = false;
2647 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2649 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2650 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2651 i->blocks = (uint32_t)(nFreeBytes / 4096);
2653 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2654 if (0 == j->compare(disk_drive)) {
2655 volume_found = true;
2660 if (!volume_found) {
2661 scanned_volumes.push_back(disk_drive);
2662 _total_free_4k_blocks += i->blocks;
2667 if (0 == _total_free_4k_blocks) {
2668 strncpy (disk_drive, path().c_str(), 3);
2671 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2673 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2674 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2675 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2682 Session::get_best_session_directory_for_new_audio ()
2684 vector<space_and_path>::iterator i;
2685 string result = _session_dir->root_path();
2687 /* handle common case without system calls */
2689 if (session_dirs.size() == 1) {
2693 /* OK, here's the algorithm we're following here:
2695 We want to select which directory to use for
2696 the next file source to be created. Ideally,
2697 we'd like to use a round-robin process so as to
2698 get maximum performance benefits from splitting
2699 the files across multiple disks.
2701 However, in situations without much diskspace, an
2702 RR approach may end up filling up a filesystem
2703 with new files while others still have space.
2704 Its therefore important to pay some attention to
2705 the freespace in the filesystem holding each
2706 directory as well. However, if we did that by
2707 itself, we'd keep creating new files in the file
2708 system with the most space until it was as full
2709 as all others, thus negating any performance
2710 benefits of this RAID-1 like approach.
2712 So, we use a user-configurable space threshold. If
2713 there are at least 2 filesystems with more than this
2714 much space available, we use RR selection between them.
2715 If not, then we pick the filesystem with the most space.
2717 This gets a good balance between the two
2721 refresh_disk_space ();
2723 int free_enough = 0;
2725 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2726 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2731 if (free_enough >= 2) {
2732 /* use RR selection process, ensuring that the one
2736 i = last_rr_session_dir;
2739 if (++i == session_dirs.end()) {
2740 i = session_dirs.begin();
2743 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2744 SessionDirectory sdir(i->path);
2745 if (sdir.create ()) {
2747 last_rr_session_dir = i;
2752 } while (i != last_rr_session_dir);
2756 /* pick FS with the most freespace (and that
2757 seems to actually work ...)
2760 vector<space_and_path> sorted;
2761 space_and_path_ascending_cmp cmp;
2763 sorted = session_dirs;
2764 sort (sorted.begin(), sorted.end(), cmp);
2766 for (i = sorted.begin(); i != sorted.end(); ++i) {
2767 SessionDirectory sdir(i->path);
2768 if (sdir.create ()) {
2770 last_rr_session_dir = i;
2780 Session::automation_dir () const
2782 return Glib::build_filename (_path, automation_dir_name);
2786 Session::analysis_dir () const
2788 return Glib::build_filename (_path, analysis_dir_name);
2792 Session::plugins_dir () const
2794 return Glib::build_filename (_path, plugins_dir_name);
2798 Session::externals_dir () const
2800 return Glib::build_filename (_path, externals_dir_name);
2804 Session::load_bundles (XMLNode const & node)
2806 XMLNodeList nlist = node.children();
2807 XMLNodeConstIterator niter;
2811 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2812 if ((*niter)->name() == "InputBundle") {
2813 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2814 } else if ((*niter)->name() == "OutputBundle") {
2815 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2817 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2826 Session::load_route_groups (const XMLNode& node, int version)
2828 XMLNodeList nlist = node.children();
2829 XMLNodeConstIterator niter;
2833 if (version >= 3000) {
2835 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2836 if ((*niter)->name() == "RouteGroup") {
2837 RouteGroup* rg = new RouteGroup (*this, "");
2838 add_route_group (rg);
2839 rg->set_state (**niter, version);
2843 } else if (version < 3000) {
2845 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2846 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2847 RouteGroup* rg = new RouteGroup (*this, "");
2848 add_route_group (rg);
2849 rg->set_state (**niter, version);
2858 state_file_filter (const string &str, void* /*arg*/)
2860 return (str.length() > strlen(statefile_suffix) &&
2861 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2865 remove_end(string state)
2867 string statename(state);
2869 string::size_type start,end;
2870 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2871 statename = statename.substr (start+1);
2874 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2875 end = statename.length();
2878 return string(statename.substr (0, end));
2882 Session::possible_states (string path)
2884 vector<string> states;
2885 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2887 transform(states.begin(), states.end(), states.begin(), remove_end);
2889 sort (states.begin(), states.end());
2895 Session::possible_states () const
2897 return possible_states(_path);
2901 Session::new_route_group (const std::string& name)
2903 RouteGroup* rg = NULL;
2905 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2906 if ((*i)->name () == name) {
2913 rg = new RouteGroup (*this, name);
2914 add_route_group (rg);
2920 Session::add_route_group (RouteGroup* g)
2922 _route_groups.push_back (g);
2923 route_group_added (g); /* EMIT SIGNAL */
2925 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2926 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2927 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2933 Session::remove_route_group (RouteGroup& rg)
2935 list<RouteGroup*>::iterator i;
2937 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2938 _route_groups.erase (i);
2941 route_group_removed (); /* EMIT SIGNAL */
2945 /** Set a new order for our route groups, without adding or removing any.
2946 * @param groups Route group list in the new order.
2949 Session::reorder_route_groups (list<RouteGroup*> groups)
2951 _route_groups = groups;
2953 route_groups_reordered (); /* EMIT SIGNAL */
2959 Session::route_group_by_name (string name)
2961 list<RouteGroup *>::iterator i;
2963 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2964 if ((*i)->name() == name) {
2972 Session::all_route_group() const
2974 return *_all_route_group;
2978 Session::add_commands (vector<Command*> const & cmds)
2980 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2986 Session::add_command (Command* const cmd)
2988 assert (_current_trans);
2989 DEBUG_UNDO_HISTORY (
2990 string_compose ("Current Undo Transaction %1, adding command: %2",
2991 _current_trans->name (),
2993 _current_trans->add_command (cmd);
2996 PBD::StatefulDiffCommand*
2997 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2999 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
3005 Session::begin_reversible_command (const string& name)
3007 begin_reversible_command (g_quark_from_string (name.c_str ()));
3010 /** Begin a reversible command using a GQuark to identify it.
3011 * begin_reversible_command() and commit_reversible_command() calls may be nested,
3012 * but there must be as many begin...()s as there are commit...()s.
3015 Session::begin_reversible_command (GQuark q)
3017 /* If nested begin/commit pairs are used, we create just one UndoTransaction
3018 to hold all the commands that are committed. This keeps the order of
3019 commands correct in the history.
3022 if (_current_trans == 0) {
3023 DEBUG_UNDO_HISTORY (string_compose (
3024 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
3026 /* start a new transaction */
3027 assert (_current_trans_quarks.empty ());
3028 _current_trans = new UndoTransaction();
3029 _current_trans->set_name (g_quark_to_string (q));
3031 DEBUG_UNDO_HISTORY (
3032 string_compose ("Begin Reversible Command, current transaction: %1",
3033 _current_trans->name ()));
3036 _current_trans_quarks.push_front (q);
3040 Session::abort_reversible_command ()
3042 if (_current_trans != 0) {
3043 DEBUG_UNDO_HISTORY (
3044 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
3045 _current_trans->clear();
3046 delete _current_trans;
3048 _current_trans_quarks.clear();
3053 Session::commit_reversible_command (Command *cmd)
3055 assert (_current_trans);
3056 assert (!_current_trans_quarks.empty ());
3061 DEBUG_UNDO_HISTORY (
3062 string_compose ("Current Undo Transaction %1, adding command: %2",
3063 _current_trans->name (),
3065 _current_trans->add_command (cmd);
3068 DEBUG_UNDO_HISTORY (
3069 string_compose ("Commit Reversible Command, current transaction: %1",
3070 _current_trans->name ()));
3072 _current_trans_quarks.pop_front ();
3074 if (!_current_trans_quarks.empty ()) {
3075 DEBUG_UNDO_HISTORY (
3076 string_compose ("Commit Reversible Command, transaction is not "
3077 "top-level, current transaction: %1",
3078 _current_trans->name ()));
3079 /* the transaction we're committing is not the top-level one */
3083 if (_current_trans->empty()) {
3084 /* no commands were added to the transaction, so just get rid of it */
3085 DEBUG_UNDO_HISTORY (
3086 string_compose ("Commit Reversible Command, No commands were "
3087 "added to current transaction: %1",
3088 _current_trans->name ()));
3089 delete _current_trans;
3094 gettimeofday (&now, 0);
3095 _current_trans->set_timestamp (now);
3097 _history.add (_current_trans);
3102 accept_all_audio_files (const string& path, void* /*arg*/)
3104 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3108 if (!AudioFileSource::safe_audio_file_extension (path)) {
3116 accept_all_midi_files (const string& path, void* /*arg*/)
3118 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3122 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3123 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3124 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3128 accept_all_state_files (const string& path, void* /*arg*/)
3130 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3134 std::string const statefile_ext (statefile_suffix);
3135 if (path.length() >= statefile_ext.length()) {
3136 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3143 Session::find_all_sources (string path, set<string>& result)
3148 if (!tree.read (path)) {
3152 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3157 XMLNodeConstIterator niter;
3159 nlist = node->children();
3163 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3165 XMLProperty const * prop;
3167 if ((prop = (*niter)->property (X_("type"))) == 0) {
3171 DataType type (prop->value());
3173 if ((prop = (*niter)->property (X_("name"))) == 0) {
3177 if (Glib::path_is_absolute (prop->value())) {
3178 /* external file, ignore */
3186 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3187 result.insert (found_path);
3195 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3197 vector<string> state_files;
3199 string this_snapshot_path;
3205 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3206 ripped = ripped.substr (0, ripped.length() - 1);
3209 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3211 if (state_files.empty()) {
3216 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3217 this_snapshot_path += statefile_suffix;
3219 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3221 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3223 if (exclude_this_snapshot && *i == this_snapshot_path) {
3224 cerr << "\texcluded\n";
3229 if (find_all_sources (*i, result) < 0) {
3237 struct RegionCounter {
3238 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3239 AudioSourceList::iterator iter;
3240 boost::shared_ptr<Region> region;
3243 RegionCounter() : count (0) {}
3247 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3249 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3250 return r.value_or (1);
3254 Session::cleanup_regions ()
3256 bool removed = false;
3257 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3259 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3261 uint32_t used = _playlists->region_use_count (i->second);
3263 if (used == 0 && !i->second->automatic ()) {
3264 boost::weak_ptr<Region> w = i->second;
3267 RegionFactory::map_remove (w);
3274 // re-check to remove parent references of compound regions
3275 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3276 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3280 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3281 if (0 == _playlists->region_use_count (i->second)) {
3282 boost::weak_ptr<Region> w = i->second;
3284 RegionFactory::map_remove (w);
3291 /* dump the history list */
3298 Session::can_cleanup_peakfiles () const
3300 if (deletion_in_progress()) {
3303 if (!_writable || cannot_save ()) {
3304 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3307 if (record_status() == Recording) {
3308 error << _("Cannot cleanup peak-files while recording") << endmsg;
3315 Session::cleanup_peakfiles ()
3317 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3322 assert (can_cleanup_peakfiles ());
3323 assert (!peaks_cleanup_in_progres());
3325 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3327 int timeout = 5000; // 5 seconds
3328 while (!SourceFactory::files_with_peaks.empty()) {
3329 Glib::usleep (1000);
3330 if (--timeout < 0) {
3331 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3332 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3337 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3338 boost::shared_ptr<AudioSource> as;
3339 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3340 as->close_peakfile();
3344 PBD::clear_directory (session_directory().peak_path());
3346 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3348 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3349 boost::shared_ptr<AudioSource> as;
3350 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3351 SourceFactory::setup_peakfile(as, true);
3358 Session::cleanup_sources (CleanupReport& rep)
3360 // FIXME: needs adaptation to midi
3362 vector<boost::shared_ptr<Source> > dead_sources;
3365 vector<string> candidates;
3366 vector<string> unused;
3367 set<string> sources_used_by_all_snapshots;
3374 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3376 _state_of_the_state = StateOfTheState (_state_of_the_state | InCleanup);
3378 /* this is mostly for windows which doesn't allow file
3379 * renaming if the file is in use. But we don't special
3380 * case it because we need to know if this causes
3381 * problems, and the easiest way to notice that is to
3382 * keep it in place for all platforms.
3385 request_stop (false);
3387 _butler->wait_until_finished ();
3389 /* consider deleting all unused playlists */
3391 if (_playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3396 /* sync the "all regions" property of each playlist with its current state */
3398 _playlists->sync_all_regions_with_regions ();
3400 /* find all un-used sources */
3405 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3407 SourceMap::iterator tmp;
3412 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3416 if (!i->second->used() && (i->second->length(i->second->natural_position()) > 0)) {
3417 dead_sources.push_back (i->second);
3418 i->second->drop_references ();
3424 /* build a list of all the possible audio directories for the session */
3426 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3427 SessionDirectory sdir ((*i).path);
3428 asp += sdir.sound_path();
3430 audio_path += asp.to_string();
3433 /* build a list of all the possible midi directories for the session */
3435 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3436 SessionDirectory sdir ((*i).path);
3437 msp += sdir.midi_path();
3439 midi_path += msp.to_string();
3441 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3442 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3444 /* add sources from all other snapshots as "used", but don't use this
3445 snapshot because the state file on disk still references sources we
3446 may have already dropped.
3449 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3451 /* Although the region factory has a list of all regions ever created
3452 * for this session, we're only interested in regions actually in
3453 * playlists right now. So merge all playlist regions lists together.
3455 * This will include the playlists used within compound regions.
3458 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3460 /* add our current source list
3463 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3464 boost::shared_ptr<FileSource> fs;
3465 SourceMap::iterator tmp = i;
3468 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3474 /* this is mostly for windows which doesn't allow file
3475 * renaming if the file is in use. But we do not special
3476 * case it because we need to know if this causes
3477 * problems, and the easiest way to notice that is to
3478 * keep it in place for all platforms.
3483 if (!fs->is_stub()) {
3485 /* Note that we're checking a list of all
3486 * sources across all snapshots with the list
3487 * of sources used by this snapshot.
3490 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3491 /* this source is in use by this snapshot */
3492 sources_used_by_all_snapshots.insert (fs->path());
3493 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3495 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3496 /* this source is NOT in use by this snapshot */
3498 /* remove all related regions from RegionFactory master list */
3500 RegionFactory::remove_regions_using_source (i->second);
3502 /* remove from our current source list
3503 * also. We may not remove it from
3504 * disk, because it may be used by
3505 * other snapshots, but it isn't used inside this
3506 * snapshot anymore, so we don't need a
3517 /* now check each candidate source to see if it exists in the list of
3518 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3521 cerr << "Candidates: " << candidates.size() << endl;
3522 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3524 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3529 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3531 tmppath1 = canonical_path (spath);
3532 tmppath2 = canonical_path ((*i));
3534 cerr << "\t => " << tmppath2 << endl;
3536 if (tmppath1 == tmppath2) {
3543 unused.push_back (spath);
3547 cerr << "Actually unused: " << unused.size() << endl;
3549 if (unused.empty()) {
3555 /* now try to move all unused files into the "dead" directory(ies) */
3557 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3562 /* don't move the file across filesystems, just
3563 * stick it in the `dead_dir_name' directory
3564 * on whichever filesystem it was already on.
3567 if ((*x).find ("/sounds/") != string::npos) {
3569 /* old school, go up 1 level */
3571 newpath = Glib::path_get_dirname (*x); // "sounds"
3572 newpath = Glib::path_get_dirname (newpath); // "session-name"
3576 /* new school, go up 4 levels */
3578 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3579 newpath = Glib::path_get_dirname (newpath); // "session-name"
3580 newpath = Glib::path_get_dirname (newpath); // "interchange"
3581 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3584 newpath = Glib::build_filename (newpath, dead_dir_name);
3586 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3587 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3591 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3593 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3595 /* the new path already exists, try versioning */
3597 char buf[PATH_MAX+1];
3601 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3604 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3605 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3609 if (version == 999) {
3610 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3614 newpath = newpath_v;
3619 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3620 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3621 newpath, g_strerror (errno)) << endmsg;
3625 /* see if there an easy to find peakfile for this file, and remove it. */
3627 string base = Glib::path_get_basename (*x);
3628 base += "%A"; /* this is what we add for the channel suffix of all native files,
3629 * or for the first channel of embedded files. it will miss
3630 * some peakfiles for other channels
3632 string peakpath = construct_peak_filepath (base);
3634 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3635 if (::g_unlink (peakpath.c_str ()) != 0) {
3636 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3637 g_strerror (errno)) << endmsg;
3638 /* try to back out */
3639 ::g_rename (newpath.c_str (), _path.c_str ());
3644 rep.paths.push_back (*x);
3645 rep.space += statbuf.st_size;
3648 /* dump the history list */
3652 /* save state so we don't end up a session file
3653 * referring to non-existent sources.
3660 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
3666 Session::cleanup_trash_sources (CleanupReport& rep)
3668 // FIXME: needs adaptation for MIDI
3670 vector<space_and_path>::iterator i;
3676 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3678 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3680 clear_directory (dead_dir, &rep.space, &rep.paths);
3687 Session::set_dirty ()
3689 /* return early if there's nothing to do */
3694 /* never mark session dirty during loading */
3695 if (loading () || deletion_in_progress ()) {
3699 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3700 DirtyChanged(); /* EMIT SIGNAL */
3704 Session::set_clean ()
3706 bool was_dirty = dirty();
3708 _state_of_the_state = Clean;
3711 DirtyChanged(); /* EMIT SIGNAL */
3716 Session::unset_dirty (bool emit_dirty_changed)
3718 bool was_dirty = dirty();
3720 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Dirty));
3722 if (was_dirty && emit_dirty_changed) {
3723 DirtyChanged (); /* EMIT SIGNAL */
3728 Session::set_deletion_in_progress ()
3730 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3734 Session::clear_deletion_in_progress ()
3736 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3740 Session::add_controllable (boost::shared_ptr<Controllable> c)
3742 /* this adds a controllable to the list managed by the Session.
3743 this is a subset of those managed by the Controllable class
3744 itself, and represents the only ones whose state will be saved
3745 as part of the session.
3748 Glib::Threads::Mutex::Lock lm (controllables_lock);
3749 controllables.insert (c);
3752 boost::shared_ptr<Controllable>
3753 Session::controllable_by_id (const PBD::ID& id)
3755 Glib::Threads::Mutex::Lock lm (controllables_lock);
3757 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3758 if ((*i)->id() == id) {
3763 return boost::shared_ptr<Controllable>();
3766 boost::shared_ptr<AutomationControl>
3767 Session::automation_control_by_id (const PBD::ID& id)
3769 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3773 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3776 Stateful::add_instant_xml (node, _path);
3779 if (write_to_config) {
3780 Config->add_instant_xml (node);
3785 Session::instant_xml (const string& node_name)
3787 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3788 if (get_disable_all_loaded_plugins ()) {
3792 return Stateful::instant_xml (node_name, _path);
3796 Session::save_history (string snapshot_name)
3804 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3805 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3809 if (snapshot_name.empty()) {
3810 snapshot_name = _current_snapshot_name;
3813 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3814 const string backup_filename = history_filename + backup_suffix;
3815 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3816 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3818 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3819 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3820 error << _("could not backup old history file, current history not saved") << endmsg;
3825 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3827 if (!tree.write (xml_path))
3829 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3831 if (g_remove (xml_path.c_str()) != 0) {
3832 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3833 xml_path, g_strerror (errno)) << endmsg;
3835 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3836 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3837 backup_path, g_strerror (errno)) << endmsg;
3847 Session::restore_history (string snapshot_name)
3851 if (snapshot_name.empty()) {
3852 snapshot_name = _current_snapshot_name;
3855 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3856 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3858 info << "Loading history from " << xml_path << endmsg;
3860 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3861 info << string_compose (_("%1: no history file \"%2\" for this session."),
3862 _name, xml_path) << endmsg;
3866 if (!tree.read (xml_path)) {
3867 error << string_compose (_("Could not understand session history file \"%1\""),
3868 xml_path) << endmsg;
3875 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3883 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3884 !t->get_property ("tv-usec", tv_usec)) {
3888 UndoTransaction* ut = new UndoTransaction ();
3889 ut->set_name (name);
3893 tv.tv_usec = tv_usec;
3894 ut->set_timestamp(tv);
3896 for (XMLNodeConstIterator child_it = t->children().begin();
3897 child_it != t->children().end(); child_it++)
3899 XMLNode *n = *child_it;
3902 if (n->name() == "MementoCommand" ||
3903 n->name() == "MementoUndoCommand" ||
3904 n->name() == "MementoRedoCommand") {
3906 if ((c = memento_command_factory(n))) {
3910 } else if (n->name() == "NoteDiffCommand") {
3911 PBD::ID id (n->property("midi-source")->value());
3912 boost::shared_ptr<MidiSource> midi_source =
3913 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3915 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3917 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3920 } else if (n->name() == "SysExDiffCommand") {
3922 PBD::ID id (n->property("midi-source")->value());
3923 boost::shared_ptr<MidiSource> midi_source =
3924 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3926 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3928 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3931 } else if (n->name() == "PatchChangeDiffCommand") {
3933 PBD::ID id (n->property("midi-source")->value());
3934 boost::shared_ptr<MidiSource> midi_source =
3935 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3937 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3939 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3942 } else if (n->name() == "StatefulDiffCommand") {
3943 if ((c = stateful_diff_command_factory (n))) {
3944 ut->add_command (c);
3947 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3958 Session::config_changed (std::string p, bool ours)
3964 if (p == "auto-loop") {
3966 } else if (p == "session-monitoring") {
3968 } else if (p == "auto-input") {
3970 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3971 /* auto-input only makes a difference if we're rolling */
3972 set_track_monitor_input_status (!config.get_auto_input());
3975 } else if (p == "punch-in") {
3979 if ((location = _locations->auto_punch_location()) != 0) {
3981 if (config.get_punch_in ()) {
3982 auto_punch_start_changed (location);
3984 clear_events (SessionEvent::PunchIn);
3988 } else if (p == "punch-out") {
3992 if ((location = _locations->auto_punch_location()) != 0) {
3994 if (config.get_punch_out()) {
3995 auto_punch_end_changed (location);
3997 clear_events (SessionEvent::PunchOut);
4001 } else if (p == "edit-mode") {
4003 Glib::Threads::Mutex::Lock lm (_playlists->lock);
4005 for (SessionPlaylists::List::iterator i = _playlists->playlists.begin(); i != _playlists->playlists.end(); ++i) {
4006 (*i)->set_edit_mode (Config->get_edit_mode ());
4009 } else if (p == "use-video-sync") {
4011 waiting_for_sync_offset = config.get_use_video_sync();
4013 } else if (p == "mmc-control") {
4015 //poke_midi_thread ();
4017 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4019 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4021 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4023 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4025 } else if (p == "midi-control") {
4027 //poke_midi_thread ();
4029 } else if (p == "raid-path") {
4031 setup_raid_path (config.get_raid_path());
4033 } else if (p == "timecode-format") {
4037 } else if (p == "video-pullup") {
4041 } else if (p == "seamless-loop") {
4043 if (play_loop && transport_rolling()) {
4044 // to reset diskstreams etc
4045 request_play_loop (true);
4048 } else if (p == "click-sound") {
4050 setup_click_sounds (1);
4052 } else if (p == "click-emphasis-sound") {
4054 setup_click_sounds (-1);
4056 } else if (p == "clicking") {
4058 if (Config->get_clicking()) {
4059 if (_click_io && click_data) { // don't require emphasis data
4066 } else if (p == "click-record-only") {
4068 _click_rec_only = Config->get_click_record_only();
4070 } else if (p == "click-gain") {
4073 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4076 } else if (p == "send-mtc") {
4078 if (Config->get_send_mtc ()) {
4079 /* mark us ready to send */
4080 next_quarter_frame_to_send = 0;
4083 } else if (p == "send-mmc") {
4085 _mmc->enable_send (Config->get_send_mmc ());
4086 if (Config->get_send_mmc ()) {
4087 /* re-initialize MMC */
4088 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4089 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4092 } else if (p == "jack-time-master") {
4094 engine().reset_timebase ();
4096 } else if (p == "native-file-header-format") {
4098 if (!first_file_header_format_reset) {
4099 reset_native_file_format ();
4102 first_file_header_format_reset = false;
4104 } else if (p == "native-file-data-format") {
4106 if (!first_file_data_format_reset) {
4107 reset_native_file_format ();
4110 first_file_data_format_reset = false;
4112 } else if (p == "external-sync") {
4113 request_sync_source (TransportMasterManager::instance().current());
4114 } else if (p == "denormal-model") {
4116 } else if (p == "history-depth") {
4117 set_history_depth (Config->get_history_depth());
4118 } else if (p == "remote-model") {
4119 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4122 } else if (p == "initial-program-change") {
4124 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4127 buf[0] = MIDI::program; // channel zero by default
4128 buf[1] = (Config->get_initial_program_change() & 0x7f);
4130 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4132 } else if (p == "solo-mute-override") {
4133 // catch_up_on_solo_mute_override ();
4134 } else if (p == "listen-position" || p == "pfl-position") {
4135 listen_position_changed ();
4136 } else if (p == "solo-control-is-listen-control") {
4137 solo_control_mode_changed ();
4138 } else if (p == "solo-mute-gain") {
4139 _solo_cut_control->Changed (true, Controllable::NoGroup);
4140 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4141 last_timecode_valid = false;
4142 } else if (p == "playback-buffer-seconds") {
4143 AudioSource::allocate_working_buffers (sample_rate());
4144 } else if (p == "ltc-sink-port") {
4145 reconnect_ltc_output ();
4146 } else if (p == "timecode-generator-offset") {
4147 ltc_tx_parse_offset();
4148 } else if (p == "auto-return-target-list") {
4150 follow_playhead_priority ();
4152 } else if (p == "use-monitor-bus") {
4153 /* NB. This is always called when constructing a session,
4154 * after restoring session state (if any),
4155 * via post_engine_init() -> Config->map_parameters()
4157 bool want_ms = Config->get_use_monitor_bus();
4158 bool have_ms = _monitor_out ? true : false;
4160 /* When loading an existing session, the config "use-monitor-bus"
4161 * is ignored. Instead the sesion-state (xml) will have added the
4162 * "monitor-route" and restored its state (and connections)
4163 * if the session has a monitor-section.
4164 * Update the config to reflect this.
4166 if (want_ms != have_ms) {
4167 Config->set_use_monitor_bus (have_ms);
4169 MonitorBusAddedOrRemoved (); /* EMIT SIGNAL */
4171 /* Otherwise, Config::set_use_monitor_bus() does
4172 * control the the presence of the monitor-section
4173 * (new sessions, user initiated change)
4175 if (want_ms && !have_ms) {
4176 add_monitor_section ();
4177 } else if (!want_ms && have_ms) {
4178 remove_monitor_section ();
4181 } else if (p == "loop-fade-choice") {
4182 last_loopend = 0; /* force locate to refill buffers with new loop boundary data */
4183 auto_loop_changed (_locations->auto_loop_location());
4190 Session::set_history_depth (uint32_t d)
4192 _history.set_depth (d);
4195 /** Connect things to the MMC object */
4197 Session::setup_midi_machine_control ()
4199 _mmc = new MIDI::MachineControl;
4201 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4202 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4204 if (!async_out || !async_out) {
4208 /* XXXX argh, passing raw pointers back into libmidi++ */
4210 MIDI::Port* mmc_in = async_in.get();
4211 MIDI::Port* mmc_out = async_out.get();
4213 _mmc->set_ports (mmc_in, mmc_out);
4215 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4216 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4217 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4218 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4219 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4220 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4221 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4222 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4223 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4224 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4225 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4226 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4227 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4229 /* also handle MIDI SPP because its so common */
4231 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4232 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4233 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4236 boost::shared_ptr<Controllable>
4237 Session::solo_cut_control() const
4239 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4240 * controls in Ardour that currently get presented to the user in the GUI that require
4241 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4243 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4244 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4247 return _solo_cut_control;
4251 Session::save_snapshot_name (const std::string & n)
4253 /* assure Stateful::_instant_xml is loaded
4254 * add_instant_xml() only adds to existing data and defaults
4255 * to use an empty Tree otherwise
4257 instant_xml ("LastUsedSnapshot");
4259 XMLNode last_used_snapshot ("LastUsedSnapshot");
4260 last_used_snapshot.set_property ("name", n);
4261 add_instant_xml (last_used_snapshot, false);
4265 Session::set_snapshot_name (const std::string & n)
4267 _current_snapshot_name = n;
4268 save_snapshot_name (n);
4272 Session::rename (const std::string& new_name)
4274 string legal_name = legalize_for_path (new_name);
4280 string const old_sources_root = _session_dir->sources_root();
4282 if (!_writable || cannot_save ()) {
4283 error << _("Cannot rename read-only session.") << endmsg;
4284 return 0; // don't show "messed up" warning
4286 if (record_status() == Recording) {
4287 error << _("Cannot rename session while recording") << endmsg;
4288 return 0; // don't show "messed up" warning
4291 StateProtector stp (this);
4296 * interchange subdirectory
4300 * Backup files are left unchanged and not renamed.
4303 /* Windows requires that we close all files before attempting the
4304 * rename. This works on other platforms, but isn't necessary there.
4305 * Leave it in place for all platforms though, since it may help
4306 * catch issues that could arise if the way Source files work ever
4307 * change (since most developers are not using Windows).
4310 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4311 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4317 /* pass one: not 100% safe check that the new directory names don't
4321 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4325 /* this is a stupid hack because Glib::path_get_dirname() is
4326 * lexical-only, and so passing it /a/b/c/ gives a different
4327 * result than passing it /a/b/c ...
4330 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4331 oldstr = oldstr.substr (0, oldstr.length() - 1);
4334 string base = Glib::path_get_dirname (oldstr);
4336 newstr = Glib::build_filename (base, legal_name);
4338 cerr << "Looking for " << newstr << endl;
4340 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4341 cerr << " exists\n";
4350 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4356 /* this is a stupid hack because Glib::path_get_dirname() is
4357 * lexical-only, and so passing it /a/b/c/ gives a different
4358 * result than passing it /a/b/c ...
4361 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4362 oldstr = oldstr.substr (0, oldstr.length() - 1);
4365 string base = Glib::path_get_dirname (oldstr);
4366 newstr = Glib::build_filename (base, legal_name);
4368 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4370 cerr << "Rename " << oldstr << " => " << newstr << endl;
4371 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4372 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4373 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4377 /* Reset path in "session dirs" */
4382 /* reset primary SessionDirectory object */
4385 (*_session_dir) = newstr;
4390 /* now rename directory below session_dir/interchange */
4392 string old_interchange_dir;
4393 string new_interchange_dir;
4395 /* use newstr here because we renamed the path
4396 * (folder/directory) that used to be oldstr to newstr above
4399 v.push_back (newstr);
4400 v.push_back (interchange_dir_name);
4401 v.push_back (Glib::path_get_basename (oldstr));
4403 old_interchange_dir = Glib::build_filename (v);
4406 v.push_back (newstr);
4407 v.push_back (interchange_dir_name);
4408 v.push_back (legal_name);
4410 new_interchange_dir = Glib::build_filename (v);
4412 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4414 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4415 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4416 old_interchange_dir, new_interchange_dir,
4419 error << string_compose (_("renaming %s as %2 failed (%3)"),
4420 old_interchange_dir, new_interchange_dir,
4429 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4430 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4432 cerr << "Rename " << oldstr << " => " << newstr << endl;
4434 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4435 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4436 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4442 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4444 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4445 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4447 cerr << "Rename " << oldstr << " => " << newstr << endl;
4449 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4450 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4451 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4456 /* remove old name from recent sessions */
4457 remove_recent_sessions (_path);
4460 /* update file source paths */
4462 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4463 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4465 string p = fs->path ();
4466 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4468 SourceFactory::setup_peakfile(i->second, true);
4472 set_snapshot_name (new_name);
4477 /* save state again to get everything just right */
4479 save_state (_current_snapshot_name);
4481 /* add to recent sessions */
4483 store_recent_sessions (new_name, _path);
4489 Session::parse_stateful_loading_version (const std::string& version)
4491 if (version.empty ()) {
4492 /* no version implies very old version of Ardour */
4496 if (version.find ('.') != string::npos) {
4497 /* old school version format */
4498 if (version[0] == '2') {
4504 return string_to<int32_t>(version);
4509 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4511 bool found_sr = false;
4512 bool found_data_format = false;
4513 std::string version;
4514 program_version = "";
4516 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4520 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4524 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4527 xmlFreeParserCtxt(ctxt);
4531 xmlNodePtr node = xmlDocGetRootElement(doc);
4534 xmlFreeParserCtxt(ctxt);
4539 /* sample rate & version*/
4542 for (attr = node->properties; attr; attr = attr->next) {
4543 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4544 version = std::string ((char*)attr->children->content);
4546 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4547 sample_rate = atoi ((char*)attr->children->content);
4552 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4556 if ((parse_stateful_loading_version(version) / 1000L) <= 2) {
4557 /* sample-format '0' is implicit */
4558 data_format = FormatFloat;
4559 found_data_format = true;
4562 node = node->children;
4563 while (node != NULL) {
4564 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4565 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4567 program_version = string ((const char*)val);
4568 size_t sep = program_version.find_first_of("-");
4569 if (sep != string::npos) {
4570 program_version = program_version.substr (0, sep);
4575 if (strcmp((const char*) node->name, "Config")) {
4579 for (node = node->children; node; node = node->next) {
4580 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4581 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4583 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4586 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4588 found_data_format = true;
4589 } catch (PBD::unknown_enumeration& e) {}
4599 xmlFreeParserCtxt(ctxt);
4602 return (found_sr && found_data_format) ? 0 : 1;
4606 Session::get_snapshot_from_instant (const std::string& session_dir)
4608 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4610 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4615 if (!tree.read (instant_xml_path)) {
4619 XMLProperty const * prop;
4620 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4621 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4622 return prop->value();
4628 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4629 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4632 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4636 SourcePathMap source_path_map;
4638 boost::shared_ptr<AudioFileSource> afs;
4643 Glib::Threads::Mutex::Lock lm (source_lock);
4645 cerr << " total sources = " << sources.size();
4647 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4648 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4654 if (fs->within_session()) {
4658 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4659 source_path_map[fs->path()].push_back (fs);
4661 SeveralFileSources v;
4663 source_path_map.insert (make_pair (fs->path(), v));
4669 cerr << " fsources = " << total << endl;
4671 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4673 /* tell caller where we are */
4675 string old_path = i->first;
4677 callback (n, total, old_path);
4679 cerr << old_path << endl;
4683 switch (i->second.front()->type()) {
4684 case DataType::AUDIO:
4685 new_path = new_audio_source_path_for_embedded (old_path);
4688 case DataType::MIDI:
4689 /* XXX not implemented yet */
4693 if (new_path.empty()) {
4697 cerr << "Move " << old_path << " => " << new_path << endl;
4699 if (!copy_file (old_path, new_path)) {
4700 cerr << "failed !\n";
4704 /* make sure we stop looking in the external
4705 dir/folder. Remember, this is an all-or-nothing
4706 operations, it doesn't merge just some files.
4708 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4710 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4711 (*f)->set_path (new_path);
4716 save_state ("", false, false);
4722 bool accept_all_files (string const &, void *)
4728 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4730 /* 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.
4735 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4737 // old_path must be in within_session ()
4738 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4740 v.push_back (new_session_folder); /* full path */
4741 v.push_back (interchange_dir_name);
4742 v.push_back (new_session_name); /* just one directory/folder */
4743 v.push_back (typedir);
4744 v.push_back (Glib::path_get_basename (old_path));
4746 return Glib::build_filename (v);
4750 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4753 v.push_back (new_session_folder); /* full path */
4754 v.push_back (interchange_dir_name);
4755 v.push_back (new_session_name);
4756 v.push_back (ARDOUR::sound_dir_name);
4757 v.push_back (filename);
4759 return Glib::build_filename (v);
4763 Session::save_as (SaveAs& saveas)
4765 vector<string> files;
4766 string current_folder = Glib::path_get_dirname (_path);
4767 string new_folder = legalize_for_path (saveas.new_name);
4768 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4769 int64_t total_bytes = 0;
4773 int32_t internal_file_cnt = 0;
4775 vector<string> do_not_copy_extensions;
4776 do_not_copy_extensions.push_back (statefile_suffix);
4777 do_not_copy_extensions.push_back (pending_suffix);
4778 do_not_copy_extensions.push_back (backup_suffix);
4779 do_not_copy_extensions.push_back (temp_suffix);
4780 do_not_copy_extensions.push_back (history_suffix);
4782 /* get total size */
4784 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4786 /* need to clear this because
4787 * find_files_matching_filter() is cumulative
4792 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4794 all += files.size();
4796 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4798 g_stat ((*i).c_str(), &gsb);
4799 total_bytes += gsb.st_size;
4803 /* save old values so we can switch back if we are not switching to the new session */
4805 string old_path = _path;
4806 string old_name = _name;
4807 string old_snapshot = _current_snapshot_name;
4808 string old_sd = _session_dir->root_path();
4809 vector<string> old_search_path[DataType::num_types];
4810 string old_config_search_path[DataType::num_types];
4812 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4813 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4814 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4815 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4817 /* switch session directory */
4819 (*_session_dir) = to_dir;
4821 /* create new tree */
4823 if (!_session_dir->create()) {
4824 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4829 /* copy all relevant files. Find each location in session_dirs,
4830 * and copy files from there to target.
4833 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4835 /* need to clear this because
4836 * find_files_matching_filter() is cumulative
4841 const size_t prefix_len = (*sd).path.size();
4843 /* Work just on the files within this session dir */
4845 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4847 /* add dir separator to protect against collisions with
4848 * track names (e.g. track named "audiofiles" or
4852 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4853 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4854 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4856 /* copy all the files. Handling is different for media files
4857 than others because of the *silly* subtree we have below the interchange
4858 folder. That really was a bad idea, but I'm not fixing it as part of
4859 implementing ::save_as().
4862 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4864 std::string from = *i;
4867 string filename = Glib::path_get_basename (from);
4868 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4869 if (filename == ".DS_STORE") {
4874 if (from.find (audiofile_dir_string) != string::npos) {
4876 /* audio file: only copy if asked */
4878 if (saveas.include_media && saveas.copy_media) {
4880 string to = make_new_media_path (*i, to_dir, new_folder);
4882 info << "media file copying from " << from << " to " << to << endmsg;
4884 if (!copy_file (from, to)) {
4885 throw Glib::FileError (Glib::FileError::IO_ERROR,
4886 string_compose(_("\ncopying \"%1\" failed !"), from));
4890 /* we found media files inside the session folder */
4892 internal_file_cnt++;
4894 } else if (from.find (midifile_dir_string) != string::npos) {
4896 /* midi file: always copy unless
4897 * creating an empty new session
4900 if (saveas.include_media) {
4902 string to = make_new_media_path (*i, to_dir, new_folder);
4904 info << "media file copying from " << from << " to " << to << endmsg;
4906 if (!copy_file (from, to)) {
4907 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4911 /* we found media files inside the session folder */
4913 internal_file_cnt++;
4915 } else if (from.find (analysis_dir_string) != string::npos) {
4917 /* make sure analysis dir exists in
4918 * new session folder, but we're not
4919 * copying analysis files here, see
4923 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4928 /* normal non-media file. Don't copy state, history, etc.
4931 bool do_copy = true;
4933 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4934 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4935 /* end of filename matches extension, do not copy file */
4941 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4942 /* don't copy peakfiles if
4943 * we're not copying media
4949 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4951 info << "attempting to make directory/folder " << to << endmsg;
4953 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4954 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4957 info << "attempting to copy " << from << " to " << to << endmsg;
4959 if (!copy_file (from, to)) {
4960 throw Glib::FileError (Glib::FileError::IO_ERROR,
4961 string_compose(_("\ncopying \"%1\" failed !"), from));
4966 /* measure file size even if we're not going to copy so that our Progress
4967 signals are correct, since we included these do-not-copy files
4968 in the computation of the total size and file count.
4972 g_stat (from.c_str(), &gsb);
4973 copied += gsb.st_size;
4976 double fraction = (double) copied / total_bytes;
4978 bool keep_going = true;
4980 if (saveas.copy_media) {
4982 /* no need or expectation of this if
4983 * media is not being copied, because
4984 * it will be fast(ish).
4987 /* tell someone "X percent, file M of N"; M is one-based */
4989 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4997 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
5003 /* copy optional folders, if any */
5005 string old = plugins_dir ();
5006 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5007 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5008 copy_files (old, newdir);
5011 old = externals_dir ();
5012 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5013 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5014 copy_files (old, newdir);
5017 old = automation_dir ();
5018 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5019 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5020 copy_files (old, newdir);
5023 if (saveas.include_media) {
5025 if (saveas.copy_media) {
5026 #ifndef PLATFORM_WINDOWS
5027 /* There are problems with analysis files on
5028 * Windows, because they used a colon in their
5029 * names as late as 4.0. Colons are not legal
5030 * under Windows even if NTFS allows them.
5032 * This is a tricky problem to solve so for
5033 * just don't copy these files. They will be
5034 * regenerated as-needed anyway, subject to the
5035 * existing issue that the filenames will be
5036 * rejected by Windows, which is a separate
5037 * problem (though related).
5040 /* only needed if we are copying media, since the
5041 * analysis data refers to media data
5044 old = analysis_dir ();
5045 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5046 string newdir = Glib::build_filename (to_dir, "analysis");
5047 copy_files (old, newdir);
5049 #endif /* PLATFORM_WINDOWS */
5054 set_snapshot_name (saveas.new_name);
5055 _name = saveas.new_name;
5057 if (saveas.include_media && !saveas.copy_media) {
5059 /* reset search paths of the new session (which we're pretending to be right now) to
5060 include the original session search path, so we can still find all audio.
5063 if (internal_file_cnt) {
5064 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5065 ensure_search_path_includes (*s, DataType::AUDIO);
5066 cerr << "be sure to include " << *s << " for audio" << endl;
5069 /* we do not do this for MIDI because we copy
5070 all MIDI files if saveas.include_media is
5076 bool was_dirty = dirty ();
5078 save_default_options ();
5080 if (saveas.copy_media && saveas.copy_external) {
5081 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5082 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5086 saveas.final_session_folder_name = _path;
5088 store_recent_sessions (_name, _path);
5090 if (!saveas.switch_to) {
5092 /* save the new state */
5094 save_state ("", false, false, !saveas.include_media);
5096 /* switch back to the way things were */
5100 set_snapshot_name (old_snapshot);
5102 (*_session_dir) = old_sd;
5108 if (internal_file_cnt) {
5109 /* reset these to their original values */
5110 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5111 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5116 /* prune session dirs, and update disk space statistics
5121 session_dirs.clear ();
5122 session_dirs.push_back (sp);
5123 refresh_disk_space ();
5125 _writable = exists_and_writable (_path);
5127 /* ensure that all existing tracks reset their current capture source paths
5129 reset_write_sources (true, true);
5131 /* creating new write sources marks the session as
5132 dirty. If the new session is empty, then
5133 save_state() thinks we're saving a template and will
5134 not mark the session as clean. So do that here,
5135 before we save state.
5138 if (!saveas.include_media) {
5142 save_state ("", false, false, !saveas.include_media);
5144 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5145 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5148 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5149 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5155 if (fs->within_session()) {
5156 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5157 fs->set_path (newpath);
5162 } catch (Glib::FileError& e) {
5164 saveas.failure_message = e.what();
5166 /* recursively remove all the directories */
5168 remove_directory (to_dir);
5176 saveas.failure_message = _("unknown reason");
5178 /* recursively remove all the directories */
5180 remove_directory (to_dir);
5190 static void set_progress (Progress* p, size_t n, size_t t)
5192 p->set_progress (float (n) / float(t));
5196 Session::archive_session (const std::string& dest,
5197 const std::string& name,
5198 ArchiveEncode compress_audio,
5199 FileArchive::CompressionLevel compression_level,
5200 bool only_used_sources,
5203 if (dest.empty () || name.empty ()) {
5207 /* We are going to temporarily change some source properties,
5208 * don't allow any concurrent saves (periodic or otherwise */
5209 Glib::Threads::Mutex::Lock lm (save_source_lock);
5211 disable_record (false);
5213 /* save current values */
5214 string old_path = _path;
5215 string old_name = _name;
5216 string old_snapshot = _current_snapshot_name;
5217 string old_sd = _session_dir->root_path();
5218 string old_config_search_path[DataType::num_types];
5219 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5220 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5222 /* ensure that session-path is included in search-path */
5224 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5225 if ((*sd).path == old_path) {
5233 /* create temporary dir to save session to */
5234 #ifdef PLATFORM_WINDOWS
5235 char tmp[256] = "C:\\TEMP\\";
5236 GetTempPath (sizeof (tmp), tmp);
5238 char const* tmp = getenv("TMPDIR");
5243 if ((strlen (tmp) + 21) > 1024) {
5248 strcpy (tmptpl, tmp);
5249 strcat (tmptpl, "ardourarchive-XXXXXX");
5250 char* tmpdir = g_mkdtemp (tmptpl);
5256 std::string to_dir = std::string (tmpdir);
5258 /* switch session directory temporarily */
5259 (*_session_dir) = to_dir;
5261 if (!_session_dir->create()) {
5262 (*_session_dir) = old_sd;
5263 remove_directory (to_dir);
5267 /* prepare archive */
5268 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5270 PBD::ScopedConnectionList progress_connection;
5271 PBD::FileArchive ar (archive);
5273 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5276 /* collect files to archive */
5277 std::map<string,string> filemap;
5279 vector<string> do_not_copy_extensions;
5280 do_not_copy_extensions.push_back (statefile_suffix);
5281 do_not_copy_extensions.push_back (pending_suffix);
5282 do_not_copy_extensions.push_back (backup_suffix);
5283 do_not_copy_extensions.push_back (temp_suffix);
5284 do_not_copy_extensions.push_back (history_suffix);
5286 vector<string> blacklist_dirs;
5287 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5288 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5289 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5290 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5291 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5292 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5294 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5295 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5296 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5298 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5299 if (only_used_sources) {
5300 _playlists->sync_all_regions_with_regions ();
5301 _playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5304 /* collect audio sources for this session, calc total size for encoding
5305 * add option to only include *used* sources (see Session::cleanup_sources)
5307 size_t total_size = 0;
5309 Glib::Threads::Mutex::Lock lm (source_lock);
5311 /* build a list of used names */
5312 std::set<std::string> audio_file_names;
5313 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5314 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5317 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5318 if (!afs || afs->readable_length () == 0) {
5321 if (only_used_sources) {
5325 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5329 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5332 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5333 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
5336 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5337 if (!afs || afs->readable_length () == 0) {
5341 if (only_used_sources) {
5345 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5350 std::string from = afs->path();
5352 if (compress_audio != NO_ENCODE) {
5353 total_size += afs->readable_length ();
5355 /* copy files as-is */
5356 if (!afs->within_session()) {
5357 string to = Glib::path_get_basename (from);
5359 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5360 * - avoid conflict with files existing in interchange
5361 * - avoid conflict with other embedded sources
5363 if (audio_file_names.find (to) == audio_file_names.end ()) {
5364 // we need a new name, add a '-<num>' before the '.<ext>'
5365 string bn = to.substr (0, to.find_last_of ('.'));
5366 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5367 to = bn + "-1" + ext;
5369 while (audio_file_names.find (to) == audio_file_names.end ()) {
5370 to = bump_name_once (to, '-');
5373 audio_file_names.insert (to);
5374 filemap[from] = make_new_audio_path (to, name, name);
5376 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5378 orig_origin[afs] = afs->origin ();
5379 afs->set_origin ("");
5382 filemap[from] = make_new_media_path (from, name, name);
5389 if (compress_audio != NO_ENCODE) {
5391 progress->set_progress (2); // set to "encoding"
5392 progress->set_progress (0);
5395 Glib::Threads::Mutex::Lock lm (source_lock);
5396 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5397 if (boost::dynamic_pointer_cast<SilentFileSource> (i->second)) {
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 orig_sources[afs] = afs->path();
5415 orig_gain[afs] = afs->gain();
5417 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5419 std::string channelsuffix = "";
5420 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5421 /* embedded external multi-channel files are converted to multiple-mono */
5422 channelsuffix = string_compose ("-c%1", afs->channel ());
5424 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5425 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5427 /* avoid name collisions of external files with same name */
5428 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5429 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5431 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5432 new_path = bump_name_once (new_path, '-');
5436 progress->descend ((float)afs->readable_length () / total_size);
5440 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5441 afs->replace_file (new_path);
5442 afs->set_gain (ns->gain(), true);
5445 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5449 progress->ascend ();
5455 progress->set_progress (-1); // set to "archiving"
5456 progress->set_progress (0);
5459 /* index files relevant for this session */
5460 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5461 vector<string> files;
5463 size_t prefix_len = (*sd).path.size();
5464 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5468 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5470 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5471 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5472 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5474 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5475 std::string from = *i;
5478 string filename = Glib::path_get_basename (from);
5479 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5480 if (filename == ".DS_STORE") {
5485 if (from.find (audiofile_dir_string) != string::npos) {
5487 } else if (from.find (midifile_dir_string) != string::npos) {
5488 filemap[from] = make_new_media_path (from, name, name);
5489 } else if (from.find (videofile_dir_string) != string::npos) {
5490 filemap[from] = make_new_media_path (from, name, name);
5492 bool do_copy = true;
5493 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5494 if (from.find (*v) != string::npos) {
5499 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5500 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5507 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5513 /* write session file */
5515 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5517 save_state (name, false, false, false, true, only_used_sources);
5519 save_default_options ();
5521 size_t prefix_len = _path.size();
5522 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5526 /* collect session-state files */
5527 vector<string> files;
5528 do_not_copy_extensions.clear ();
5529 do_not_copy_extensions.push_back (history_suffix);
5531 blacklist_dirs.clear ();
5532 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5534 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5535 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5536 std::string from = *i;
5537 bool do_copy = true;
5538 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5539 if (from.find (*v) != string::npos) {
5544 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5545 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5551 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5555 /* restore original values */
5558 set_snapshot_name (old_snapshot);
5559 (*_session_dir) = old_sd;
5560 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5561 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5563 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5564 i->first->set_origin (i->second);
5566 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5567 i->first->replace_file (i->second);
5569 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5570 i->first->set_gain (i->second, true);
5573 int rv = ar.create (filemap, compression_level);
5574 remove_directory (to_dir);
5580 Session::undo (uint32_t n)
5582 if (actively_recording()) {
5590 Session::redo (uint32_t n)
5592 if (actively_recording()) {