2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
53 #include "pbd/locale_guard.h"
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/basename.h"
67 #include "pbd/debug.h"
68 #include "pbd/enumwriter.h"
69 #include "pbd/error.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/types_convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/audioregion.h"
84 #include "ardour/auditioner.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/boost_debug.h"
87 #include "ardour/butler.h"
88 #include "ardour/control_protocol_manager.h"
89 #include "ardour/directory_names.h"
90 #include "ardour/disk_reader.h"
91 #include "ardour/filename_extensions.h"
92 #include "ardour/graph.h"
93 #include "ardour/location.h"
95 #include "ardour/lv2_plugin.h"
97 #include "ardour/midi_model.h"
98 #include "ardour/midi_patch_manager.h"
99 #include "ardour/midi_region.h"
100 #include "ardour/midi_scene_changer.h"
101 #include "ardour/midi_source.h"
102 #include "ardour/midi_track.h"
103 #include "ardour/pannable.h"
104 #include "ardour/playlist_factory.h"
105 #include "ardour/playlist_source.h"
106 #include "ardour/port.h"
107 #include "ardour/processor.h"
108 #include "ardour/progress.h"
109 #include "ardour/profile.h"
110 #include "ardour/proxy_controllable.h"
111 #include "ardour/recent_sessions.h"
112 #include "ardour/region_factory.h"
113 #include "ardour/revision.h"
114 #include "ardour/route_group.h"
115 #include "ardour/send.h"
116 #include "ardour/selection.h"
117 #include "ardour/session.h"
118 #include "ardour/session_directory.h"
119 #include "ardour/session_metadata.h"
120 #include "ardour/session_playlists.h"
121 #include "ardour/session_state_utils.h"
122 #include "ardour/silentfilesource.h"
123 #include "ardour/smf_source.h"
124 #include "ardour/sndfilesource.h"
125 #include "ardour/source_factory.h"
126 #include "ardour/speakers.h"
127 #include "ardour/template_utils.h"
128 #include "ardour/tempo.h"
129 #include "ardour/ticker.h"
130 #include "ardour/types_convert.h"
131 #include "ardour/user_bundle.h"
132 #include "ardour/vca.h"
133 #include "ardour/vca_manager.h"
135 #include "control_protocol/control_protocol.h"
137 #include "LuaBridge/LuaBridge.h"
139 #include "pbd/i18n.h"
143 using namespace ARDOUR;
146 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
149 Session::pre_engine_init (string fullpath)
151 if (fullpath.empty()) {
153 throw failed_constructor();
156 /* discover canonical fullpath */
158 _path = canonical_path(fullpath);
161 if (Profile->get_trx() ) {
162 // Waves TracksLive has a usecase of session replacement with a new one.
163 // We should check session state file (<session_name>.ardour) existance
164 // to determine if the session is new or not
166 string full_session_name = Glib::build_filename( fullpath, _name );
167 full_session_name += statefile_suffix;
169 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
171 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
174 /* finish initialization that can't be done in a normal C++ constructor
178 timerclear (&last_mmc_step);
179 g_atomic_int_set (&processing_prohibited, 0);
180 g_atomic_int_set (&_record_status, Disabled);
181 g_atomic_int_set (&_playback_load, 100);
182 g_atomic_int_set (&_capture_load, 100);
184 _all_route_group->set_active (true, this);
186 if (config.get_use_video_sync()) {
187 waiting_for_sync_offset = true;
189 waiting_for_sync_offset = false;
192 last_rr_session_dir = session_dirs.begin();
194 set_history_depth (Config->get_history_depth());
196 /* default: assume simple stereo speaker configuration */
198 _speakers->setup_default_speakers (2);
200 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
201 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
202 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
203 add_controllable (_solo_cut_control);
205 /* These are all static "per-class" signals */
207 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
208 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
209 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
210 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, 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));
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 /* Reset all panners */
320 Delivery::reset_panners ();
322 /* this will cause the CPM to instantiate any protocols that are in use
323 * (or mandatory), which will pass it this Session, and then call
324 * set_state() on each instantiated protocol to match stored state.
327 ControlProtocolManager::instance().set_session (this);
329 /* This must be done after the ControlProtocolManager set_session above,
330 as it will set states for ports which the ControlProtocolManager creates.
333 // XXX set state of MIDI::Port's
334 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
336 /* And this must be done after the MIDI::Manager::set_port_states as
337 * it will try to make connections whose details are loaded by set_port_states.
342 /* Let control protocols know that we are now all connected, so they
343 * could start talking to surfaces if they want to.
346 ControlProtocolManager::instance().midi_connectivity_established ();
348 if (_is_new && !no_auto_connect()) {
349 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
350 auto_connect_master_bus ();
353 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
355 /* update latencies */
357 initialize_latencies ();
359 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
360 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
361 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
363 } catch (AudioEngine::PortRegistrationFailure& err) {
364 error << err.what() << endmsg;
366 } catch (std::exception const & e) {
367 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
370 error << _("Unknown exception during session setup") << endmsg;
374 BootMessage (_("Reset Remote Controls"));
376 // send_full_time_code (0);
377 _engine.transport_locate (0);
379 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
380 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
382 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
385 /* initial program change will be delivered later; see ::config_changed() */
387 _state_of_the_state = Clean;
389 Port::set_connecting_blocked (false);
391 DirtyChanged (); /* EMIT SIGNAL */
395 } else if (state_was_pending) {
397 remove_pending_capture_state ();
398 state_was_pending = false;
401 /* Now, finally, we can fill the playback buffers */
403 BootMessage (_("Filling playback buffers"));
405 boost::shared_ptr<RouteList> rl = routes.reader();
406 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
407 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
408 if (trk && !trk->is_private_route()) {
409 trk->seek (_transport_sample, true);
417 Session::session_loaded ()
421 _state_of_the_state = Clean;
423 DirtyChanged (); /* EMIT SIGNAL */
427 } else if (state_was_pending) {
429 remove_pending_capture_state ();
430 state_was_pending = false;
433 /* Now, finally, we can fill the playback buffers */
435 BootMessage (_("Filling playback buffers"));
436 force_locate (_transport_sample, false);
440 Session::raid_path () const
442 Searchpath raid_search_path;
444 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
445 raid_search_path += (*i).path;
448 return raid_search_path.to_string ();
452 Session::setup_raid_path (string path)
461 session_dirs.clear ();
463 Searchpath search_path(path);
464 Searchpath sound_search_path;
465 Searchpath midi_search_path;
467 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
469 sp.blocks = 0; // not needed
470 session_dirs.push_back (sp);
472 SessionDirectory sdir(sp.path);
474 sound_search_path += sdir.sound_path ();
475 midi_search_path += sdir.midi_path ();
478 // reset the round-robin soundfile path thingie
479 last_rr_session_dir = session_dirs.begin();
483 Session::path_is_within_session (const std::string& path)
485 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
486 if (PBD::path_is_within (i->path, path)) {
494 Session::ensure_subdirs ()
498 dir = session_directory().peak_path();
500 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
501 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
505 dir = session_directory().sound_path();
507 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
508 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
512 dir = session_directory().midi_path();
514 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
515 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
519 dir = session_directory().dead_path();
521 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
522 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
526 dir = session_directory().export_path();
528 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
529 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
533 dir = analysis_dir ();
535 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
536 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
540 dir = plugins_dir ();
542 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
543 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
547 dir = externals_dir ();
549 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
550 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
557 /** @param session_template directory containing session template, or empty.
558 * Caller must not hold process lock.
561 Session::create (const string& session_template, BusProfile* bus_profile)
563 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
564 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
568 if (ensure_subdirs ()) {
572 _writable = exists_and_writable (_path);
574 if (!session_template.empty()) {
575 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
577 FILE* in = g_fopen (in_path.c_str(), "rb");
580 /* no need to call legalize_for_path() since the string
581 * in session_template is already a legal path name
583 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
585 FILE* out = g_fopen (out_path.c_str(), "wb");
589 stringstream new_session;
592 size_t charsRead = fread (buf, sizeof(char), 1024, in);
595 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
600 if (charsRead == 0) {
603 new_session.write (buf, charsRead);
607 string file_contents = new_session.str();
608 size_t writeSize = file_contents.length();
609 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
610 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
618 if (!ARDOUR::Profile->get_trx()) {
619 /* Copy plugin state files from template to new session */
620 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
621 copy_recurse (template_plugins, plugins_dir ());
627 error << string_compose (_("Could not open %1 for writing session template"), out_path)
634 error << string_compose (_("Could not open session template %1 for reading"), in_path)
641 if (Profile->get_trx()) {
643 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
644 * Remember that this is a brand new session. Sessions
645 * loaded from saved state will get this range from the saved state.
648 set_session_range_location (0, 0);
650 /* Initial loop location, from absolute zero, length 10 seconds */
652 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
653 _locations->add (loc, true);
654 set_auto_loop_location (loc);
657 _state_of_the_state = Clean;
659 /* set up Master Out and Monitor Out if necessary */
663 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
664 if (bus_profile->master_out_channels) {
665 int rv = add_master_bus (count);
671 if (Config->get_use_monitor_bus())
672 add_monitor_section ();
680 Session::maybe_write_autosave()
682 if (dirty() && record_status() != Recording) {
683 save_state("", true);
688 Session::remove_pending_capture_state ()
690 std::string pending_state_file_path(_session_dir->root_path());
692 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
694 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
696 if (g_remove (pending_state_file_path.c_str()) != 0) {
697 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
698 pending_state_file_path, g_strerror (errno)) << endmsg;
702 /** Rename a state file.
703 * @param old_name Old snapshot name.
704 * @param new_name New snapshot name.
707 Session::rename_state (string old_name, string new_name)
709 if (old_name == _current_snapshot_name || old_name == _name) {
710 /* refuse to rename the current snapshot or the "main" one */
714 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
715 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
717 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
718 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
720 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
721 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
722 old_name, new_name, g_strerror(errno)) << endmsg;
726 /** Remove a state file.
727 * @param snapshot_name Snapshot name.
730 Session::remove_state (string snapshot_name)
732 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
733 // refuse to remove the current snapshot or the "main" one
737 std::string xml_path(_session_dir->root_path());
739 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
741 if (!create_backup_file (xml_path)) {
742 // don't remove it if a backup can't be made
743 // create_backup_file will log the error.
748 if (g_remove (xml_path.c_str()) != 0) {
749 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
750 xml_path, g_strerror (errno)) << endmsg;
754 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
756 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only, bool for_archive, bool only_used_assets)
758 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
761 std::string xml_path(_session_dir->root_path());
763 /* prevent concurrent saves from different threads */
765 Glib::Threads::Mutex::Lock lm (save_state_lock);
766 Glib::Threads::Mutex::Lock lx (save_source_lock, Glib::Threads::NOT_LOCK);
771 if (!_writable || (_state_of_the_state & CannotSave)) {
775 if (g_atomic_int_get(&_suspend_save)) {
779 _save_queued = false;
781 snapshot_t fork_state = NormalSave;
782 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending && !for_archive) {
783 /* snapshot, close midi */
784 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
788 const int64_t save_start_time = g_get_monotonic_time();
791 /* tell sources we're saving first, in case they write out to a new file
792 * which should be saved with the state rather than the old one */
793 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
795 i->second->session_saved();
796 } catch (Evoral::SMF::FileError& e) {
797 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
801 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, for_archive);
803 SessionSaveUnderway (); /* EMIT SIGNAL */
805 bool mark_as_clean = true;
806 if (!snapshot_name.empty() && !switch_to_snapshot) {
807 mark_as_clean = false;
811 mark_as_clean = false;
812 tree.set_root (&get_template());
814 tree.set_root (&state (false, fork_state, only_used_assets));
817 if (snapshot_name.empty()) {
818 snapshot_name = _current_snapshot_name;
819 } else if (switch_to_snapshot) {
820 set_snapshot_name (snapshot_name);
823 assert (!snapshot_name.empty());
827 /* proper save: use statefile_suffix (.ardour in English) */
829 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
831 /* make a backup copy of the old file */
833 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
834 // create_backup_file will log the error
840 /* pending save: use pending_suffix (.pending in English) */
841 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
844 std::string tmp_path(_session_dir->root_path());
845 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
848 cerr << "actually writing state to " << tmp_path << endl;
851 if (!tree.write (tmp_path)) {
852 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
853 if (g_remove (tmp_path.c_str()) != 0) {
854 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
855 tmp_path, g_strerror (errno)) << endmsg;
862 cerr << "renaming state to " << xml_path << endl;
865 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
866 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
867 tmp_path, xml_path, g_strerror(errno)) << endmsg;
868 if (g_remove (tmp_path.c_str()) != 0) {
869 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
870 tmp_path, g_strerror (errno)) << endmsg;
876 if (!pending && !for_archive) {
878 save_history (snapshot_name);
881 bool was_dirty = dirty();
883 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
886 DirtyChanged (); /* EMIT SIGNAL */
890 StateSaved (snapshot_name); /* EMIT SIGNAL */
894 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
895 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
901 Session::restore_state (string snapshot_name)
904 if (load_state (snapshot_name) == 0) {
905 set_state (*state_tree->root(), Stateful::loading_state_version);
909 // unknown_enumeration
917 Session::load_state (string snapshot_name)
922 state_was_pending = false;
924 /* check for leftover pending state from a crashed capture attempt */
926 std::string xmlpath(_session_dir->root_path());
927 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
929 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
931 /* there is pending state from a crashed capture attempt */
933 boost::optional<int> r = AskAboutPendingState();
934 if (r.get_value_or (1)) {
935 state_was_pending = true;
939 if (!state_was_pending) {
940 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
943 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
944 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
945 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
946 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
951 state_tree = new XMLTree;
955 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
957 if (!state_tree->read (xmlpath)) {
958 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
964 XMLNode const & root (*state_tree->root());
966 if (root.name() != X_("Session")) {
967 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
974 root.get_property ("version", version);
975 Stateful::loading_state_version = parse_stateful_loading_version (version);
977 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
978 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
979 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
982 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
984 std::string backup_path(_session_dir->root_path());
985 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
986 backup_path = Glib::build_filename (backup_path, backup_filename);
988 // only create a backup for a given statefile version once
990 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
992 VersionMismatch (xmlpath, backup_path);
994 if (!copy_file (xmlpath, backup_path)) {;
1000 save_snapshot_name (snapshot_name);
1006 Session::load_options (const XMLNode& node)
1008 config.set_variables (node);
1013 Session::save_default_options ()
1015 return config.save_state();
1019 Session::get_state ()
1021 /* this is not directly called, but required by PBD::Stateful */
1023 return state (false, NormalSave);
1027 Session::get_template ()
1029 /* if we don't disable rec-enable, diskstreams
1030 will believe they need to store their capture
1031 sources in their state node.
1034 disable_record (false);
1036 return state (true, NormalSave);
1039 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1040 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1043 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1045 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1048 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1052 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1055 XMLNode* node = new XMLNode("TrackState"); // XXX
1058 PlaylistSet playlists; // SessionPlaylists
1061 // these will work with new_route_from_template()
1062 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1063 child = node->add_child ("Routes");
1064 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1065 if ((*i)->is_auditioner()) {
1068 if ((*i)->is_master() || (*i)->is_monitor()) {
1071 child->add_child_nocopy ((*i)->get_state());
1072 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1074 playlists.insert (track->playlist ());
1078 // on load, Regions in the playlists need to resolve and map Source-IDs
1079 // also playlist needs to be merged or created with new-name..
1080 // ... and Diskstream in tracks adjusted to use the correct playlist
1081 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1082 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1083 child->add_child_nocopy ((*i)->get_state ());
1084 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1085 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1086 const Region::SourceList& sl = (*s)->sources ();
1087 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1088 sources.insert (*sli);
1093 child = node->add_child ("Sources");
1094 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1095 child->add_child_nocopy ((*i)->get_state ());
1096 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1098 #ifdef PLATFORM_WINDOWS
1101 string p = fs->path ();
1102 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1106 std::string sn = Glib::build_filename (path, "share.axml");
1109 tree.set_root (node);
1110 return tree.write (sn.c_str());
1114 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
1116 pl->deep_sources (*all_sources);
1121 struct route_id_compare {
1123 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1125 return r1->id () < r2->id ();
1131 Session::state (bool save_template, snapshot_t snapshot_type, bool only_used_assets)
1134 XMLNode* node = new XMLNode("Session");
1137 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1139 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1141 child = node->add_child ("ProgramVersion");
1142 child->set_property("created-with", created_with);
1144 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1145 child->set_property("modified-with", modified_with);
1147 /* store configuration settings */
1149 if (!save_template) {
1151 node->set_property ("name", _name);
1152 node->set_property ("sample-rate", _base_sample_rate);
1154 if (session_dirs.size() > 1) {
1158 vector<space_and_path>::iterator i = session_dirs.begin();
1159 vector<space_and_path>::iterator next;
1161 ++i; /* skip the first one */
1165 while (i != session_dirs.end()) {
1169 if (next != session_dirs.end()) {
1170 p += G_SEARCHPATH_SEPARATOR;
1179 child = node->add_child ("Path");
1180 child->add_content (p);
1182 node->set_property ("end-is-free", _session_range_end_is_free);
1185 /* save the ID counter */
1187 node->set_property ("id-counter", ID::counter());
1189 node->set_property ("name-counter", name_id_counter ());
1191 /* save the event ID counter */
1193 node->set_property ("event-counter", Evoral::event_id_counter());
1195 /* save the VCA counter */
1197 node->set_property ("vca-counter", VCA::get_next_vca_number());
1199 /* various options */
1201 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1202 if (!midi_port_nodes.empty()) {
1203 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1204 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1205 midi_port_stuff->add_child_nocopy (**n);
1207 node->add_child_nocopy (*midi_port_stuff);
1210 XMLNode& cfgxml (config.get_variables ());
1211 if (save_template) {
1212 /* exclude search-paths from template */
1213 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1214 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1215 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1217 node->add_child_nocopy (cfgxml);
1219 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1221 child = node->add_child ("Sources");
1223 if (!save_template) {
1224 Glib::Threads::Mutex::Lock sl (source_lock);
1226 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
1228 if (only_used_assets) {
1229 playlists->sync_all_regions_with_regions ();
1230 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
1233 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1235 /* Don't save information about non-file Sources, or
1236 * about non-destructive file sources that are empty
1237 * and unused by any regions.
1239 boost::shared_ptr<FileSource> fs;
1241 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1245 if (!fs->destructive()) {
1246 if (fs->empty() && !fs->used()) {
1251 if (only_used_assets) {
1252 /* skip only unused audio files */
1253 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (fs);
1254 if (afs && !afs->used()) {
1257 if (afs && sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
1262 if (snapshot_type != NormalSave && fs->within_session ()) {
1263 /* copy MIDI sources to new file
1265 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1266 * because the GUI (midi_region) has a direct pointer to the midi-model
1267 * of the source, as does UndoTransaction.
1269 * On the upside, .mid files are not kept open. The file is only open
1270 * when reading the model initially and when flushing the model to disk:
1271 * source->session_saved () or export.
1273 * We can change the _path of the existing source under the hood, keeping
1274 * all IDs, references and pointers intact.
1276 boost::shared_ptr<SMFSource> ms;
1277 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1278 const std::string ancestor_name = ms->ancestor_name();
1279 const std::string base = PBD::basename_nosuffix(ancestor_name);
1280 const string path = new_midi_source_path (base, false);
1282 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1283 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1284 Source::Lock lm (ms->mutex());
1286 // TODO special-case empty, removable() files: just create a new removable.
1287 // (load + write flushes the model and creates the file)
1289 ms->load_model (lm);
1291 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1292 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1294 if (snapshot_type == SnapshotKeep) {
1295 /* keep working on current session.
1297 * Save snapshot-state with the original filename.
1298 * Switch to use new path for future saves of the main session.
1300 child->add_child_nocopy (ms->get_state());
1304 * ~SMFSource unlinks removable() files.
1306 std::string npath (ms->path ());
1307 ms->replace_file (newsrc->path ());
1308 newsrc->replace_file (npath);
1310 if (snapshot_type == SwitchToSnapshot) {
1311 /* save and switch to snapshot.
1313 * Leave the old file in place (as is).
1314 * Snapshot uses new source directly
1316 child->add_child_nocopy (ms->get_state());
1323 child->add_child_nocopy (siter->second->get_state());
1327 child = node->add_child ("Regions");
1329 if (!save_template) {
1330 Glib::Threads::Mutex::Lock rl (region_lock);
1332 if (!only_used_assets) {
1333 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1334 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1335 boost::shared_ptr<Region> r = i->second;
1336 /* only store regions not attached to playlists */
1337 if (r->playlist() == 0) {
1338 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1339 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1341 child->add_child_nocopy (r->get_state ());
1347 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1349 if (!cassocs.empty()) {
1350 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1352 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1353 if (i->first->playlist () == 0 && only_used_assets) {
1356 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1357 can->set_property (X_("copy"), i->first->id());
1358 can->set_property (X_("original"), i->second->id());
1359 ca->add_child_nocopy (*can);
1360 /* see above, child is still "Regions" here */
1361 if (i->second->playlist() == 0 && only_used_assets) {
1362 if (boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>( i->second)) {
1363 child->add_child_nocopy (ar->get_basic_state ());
1365 child->add_child_nocopy (ar->get_state ());
1372 if (!save_template) {
1374 node->add_child_nocopy (_selection->get_state());
1377 node->add_child_nocopy (_locations->get_state());
1380 Locations loc (*this);
1381 const bool was_dirty = dirty();
1382 // for a template, just create a new Locations, populate it
1383 // with the default start and end, and get the state for that.
1384 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1385 range->set (max_samplepos, 0);
1387 XMLNode& locations_state = loc.get_state();
1389 if (ARDOUR::Profile->get_trx() && _locations) {
1390 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1391 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1392 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1393 locations_state.add_child_nocopy ((*i)->get_state ());
1397 node->add_child_nocopy (locations_state);
1399 /* adding a location above will have marked the session
1400 * dirty. This is an artifact, so fix it if the session wasn't
1405 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1409 child = node->add_child ("Bundles");
1411 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1412 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1413 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1415 child->add_child_nocopy (b->get_state());
1420 node->add_child_nocopy (_vca_manager->get_state());
1422 child = node->add_child ("Routes");
1424 boost::shared_ptr<RouteList> r = routes.reader ();
1426 route_id_compare cmp;
1427 RouteList xml_node_order (*r);
1428 xml_node_order.sort (cmp);
1430 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1431 if (!(*i)->is_auditioner()) {
1432 if (save_template) {
1433 child->add_child_nocopy ((*i)->get_template());
1435 child->add_child_nocopy ((*i)->get_state());
1441 playlists->add_state (node, save_template, !only_used_assets);
1443 child = node->add_child ("RouteGroups");
1444 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1445 child->add_child_nocopy ((*i)->get_state());
1449 XMLNode* gain_child = node->add_child ("Click");
1450 gain_child->add_child_nocopy (_click_io->get_state ());
1451 gain_child->add_child_nocopy (_click_gain->get_state ());
1455 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1456 ltc_input_child->add_child_nocopy (_ltc_input->get_state ());
1460 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1461 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1464 node->add_child_nocopy (_speakers->get_state());
1465 node->add_child_nocopy (_tempo_map->get_state());
1466 node->add_child_nocopy (get_control_protocol_state());
1469 node->add_child_copy (*_extra_xml);
1473 Glib::Threads::Mutex::Lock lm (lua_lock);
1476 luabridge::LuaRef savedstate ((*_lua_save)());
1477 saved = savedstate.cast<std::string>();
1479 lua.collect_garbage ();
1482 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1483 std::string b64s (b64);
1486 XMLNode* script_node = new XMLNode (X_("Script"));
1487 script_node->set_property (X_("lua"), LUA_VERSION);
1488 script_node->add_content (b64s);
1489 node->add_child_nocopy (*script_node);
1496 Session::get_control_protocol_state ()
1498 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1499 return cpm.get_state();
1503 Session::set_state (const XMLNode& node, int version)
1510 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1512 if (node.name() != X_("Session")) {
1513 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1517 node.get_property ("name", _name);
1519 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1521 _nominal_sample_rate = _base_sample_rate;
1523 assert (AudioEngine::instance()->running ());
1524 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1525 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1526 if (r.get_value_or (0)) {
1532 created_with = "unknown";
1533 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1534 child->get_property (X_("created-with"), created_with);
1537 setup_raid_path(_session_dir->root_path());
1539 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1542 if (node.get_property (X_("id-counter"), counter)) {
1543 ID::init_counter (counter);
1545 /* old sessions used a timebased counter, so fake
1546 * the startup ID counter based on a standard
1551 ID::init_counter (now);
1554 if (node.get_property (X_("name-counter"), counter)) {
1555 init_name_id_counter (counter);
1558 if (node.get_property (X_("event-counter"), counter)) {
1559 Evoral::init_event_id_counter (counter);
1562 if (node.get_property (X_("vca-counter"), counter)) {
1563 VCA::set_next_vca_number (counter);
1565 VCA::set_next_vca_number (1);
1568 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1569 _midi_ports->set_midi_port_states (child->children());
1572 IO::disable_connecting ();
1574 Stateful::save_extra_xml (node);
1576 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1577 load_options (*child);
1578 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1579 load_options (*child);
1581 error << _("Session: XML state has no options section") << endmsg;
1584 if (version >= 3000) {
1585 if ((child = find_named_node (node, "Metadata")) == 0) {
1586 warning << _("Session: XML state has no metadata section") << endmsg;
1587 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1592 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1593 _speakers->set_state (*child, version);
1596 if ((child = find_named_node (node, "Sources")) == 0) {
1597 error << _("Session: XML state has no sources section") << endmsg;
1599 } else if (load_sources (*child)) {
1603 if ((child = find_named_node (node, "TempoMap")) == 0) {
1604 error << _("Session: XML state has no Tempo Map section") << endmsg;
1606 } else if (_tempo_map->set_state (*child, version)) {
1610 if ((child = find_named_node (node, "Locations")) == 0) {
1611 error << _("Session: XML state has no locations section") << endmsg;
1613 } else if (_locations->set_state (*child, version)) {
1617 locations_changed ();
1619 if (_session_range_location) {
1620 AudioFileSource::set_header_position_offset (_session_range_location->start());
1623 if ((child = find_named_node (node, "Regions")) == 0) {
1624 error << _("Session: XML state has no Regions section") << endmsg;
1626 } else if (load_regions (*child)) {
1630 if ((child = find_named_node (node, "Playlists")) == 0) {
1631 error << _("Session: XML state has no playlists section") << endmsg;
1633 } else if (playlists->load (*this, *child)) {
1637 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1639 } else if (playlists->load_unused (*this, *child)) {
1643 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1644 if (load_compounds (*child)) {
1649 if (version >= 3000) {
1650 if ((child = find_named_node (node, "Bundles")) == 0) {
1651 warning << _("Session: XML state has no bundles section") << endmsg;
1654 /* We can't load Bundles yet as they need to be able
1655 * to convert from port names to Port objects, which can't happen until
1657 _bundle_xml_node = new XMLNode (*child);
1661 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1662 _vca_manager->set_state (*child, version);
1665 if ((child = find_named_node (node, "Routes")) == 0) {
1666 error << _("Session: XML state has no routes section") << endmsg;
1668 } else if (load_routes (*child, version)) {
1672 /* Now that we have Routes and masters loaded, connect them if appropriate */
1674 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1676 if (version >= 3000) {
1678 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1679 error << _("Session: XML state has no route groups section") << endmsg;
1681 } else if (load_route_groups (*child, version)) {
1685 } else if (version < 3000) {
1687 if ((child = find_named_node (node, "EditGroups")) == 0) {
1688 error << _("Session: XML state has no edit groups section") << endmsg;
1690 } else if (load_route_groups (*child, version)) {
1694 if ((child = find_named_node (node, "MixGroups")) == 0) {
1695 error << _("Session: XML state has no mix groups section") << endmsg;
1697 } else if (load_route_groups (*child, version)) {
1702 if ((child = find_named_node (node, "Click")) == 0) {
1703 warning << _("Session: XML state has no click section") << endmsg;
1704 } else if (_click_io) {
1705 setup_click_state (&node);
1708 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1709 ControlProtocolManager::instance().set_state (*child, version);
1712 if ((child = find_named_node (node, "Script"))) {
1713 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1714 if (!(*n)->is_content ()) { continue; }
1716 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1718 Glib::Threads::Mutex::Lock lm (lua_lock);
1719 (*_lua_load)(std::string ((const char*)buf, size));
1720 } catch (luabridge::LuaException const& e) {
1721 cerr << "LuaException:" << e.what () << endl;
1727 if ((child = find_named_node (node, X_("Selection")))) {
1728 _selection->set_state (*child, version);
1731 update_route_record_state ();
1733 /* here beginneth the second phase ... */
1734 set_snapshot_name (_current_snapshot_name);
1736 StateReady (); /* EMIT SIGNAL */
1749 Session::load_routes (const XMLNode& node, int version)
1752 XMLNodeConstIterator niter;
1753 RouteList new_routes;
1755 nlist = node.children();
1759 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1761 boost::shared_ptr<Route> route;
1763 if (version < 3000) {
1764 route = XMLRouteFactory_2X (**niter, version);
1765 } else if (version < 5000) {
1766 route = XMLRouteFactory_3X (**niter, version);
1768 route = XMLRouteFactory (**niter, version);
1772 error << _("Session: cannot create Route from XML description.") << endmsg;
1776 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1778 new_routes.push_back (route);
1781 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1783 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1785 BootMessage (_("Finished adding tracks/busses"));
1790 boost::shared_ptr<Route>
1791 Session::XMLRouteFactory (const XMLNode& node, int version)
1793 boost::shared_ptr<Route> ret;
1795 if (node.name() != "Route") {
1799 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1802 pl_prop = node.property (X_("midi-playlist"));
1805 DataType type = DataType::AUDIO;
1806 node.get_property("default-type", type);
1808 assert (type != DataType::NIL);
1812 /* has at least 1 playlist, therefore a track ... */
1814 boost::shared_ptr<Track> track;
1816 if (type == DataType::AUDIO) {
1817 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1819 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1822 if (track->init()) {
1826 if (track->set_state (node, version)) {
1830 BOOST_MARK_TRACK (track);
1834 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1835 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1838 if (r->init () == 0 && r->set_state (node, version) == 0) {
1839 BOOST_MARK_ROUTE (r);
1847 boost::shared_ptr<Route>
1848 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1850 boost::shared_ptr<Route> ret;
1852 if (node.name() != "Route") {
1856 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1858 DataType type = DataType::AUDIO;
1859 node.get_property("default-type", type);
1861 assert (type != DataType::NIL);
1865 boost::shared_ptr<Track> track;
1867 if (type == DataType::AUDIO) {
1868 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1870 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1873 if (track->init()) {
1877 if (track->set_state (node, version)) {
1881 BOOST_MARK_TRACK (track);
1885 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1886 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1888 if (r->init () == 0 && r->set_state (node, version) == 0) {
1889 BOOST_MARK_ROUTE (r);
1897 boost::shared_ptr<Route>
1898 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1900 boost::shared_ptr<Route> ret;
1902 if (node.name() != "Route") {
1906 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1908 ds_prop = node.property (X_("diskstream"));
1911 DataType type = DataType::AUDIO;
1912 node.get_property("default-type", type);
1914 assert (type != DataType::NIL);
1918 /* see comment in current ::set_state() regarding diskstream
1919 * state and DiskReader/DiskWRiter.
1922 error << _("Could not find diskstream for route") << endmsg;
1923 return boost::shared_ptr<Route> ();
1925 boost::shared_ptr<Track> track;
1927 if (type == DataType::AUDIO) {
1928 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1930 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1933 if (track->init()) {
1937 if (track->set_state (node, version)) {
1941 BOOST_MARK_TRACK (track);
1945 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1946 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1948 if (r->init () == 0 && r->set_state (node, version) == 0) {
1949 BOOST_MARK_ROUTE (r);
1958 Session::load_regions (const XMLNode& node)
1961 XMLNodeConstIterator niter;
1962 boost::shared_ptr<Region> region;
1964 nlist = node.children();
1968 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1969 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1970 error << _("Session: cannot create Region from XML description.");
1971 XMLProperty const * name = (**niter).property("name");
1974 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1985 Session::load_compounds (const XMLNode& node)
1987 XMLNodeList calist = node.children();
1988 XMLNodeConstIterator caiter;
1989 XMLProperty const * caprop;
1991 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1992 XMLNode* ca = *caiter;
1996 if ((caprop = ca->property (X_("original"))) == 0) {
1999 orig_id = caprop->value();
2001 if ((caprop = ca->property (X_("copy"))) == 0) {
2004 copy_id = caprop->value();
2006 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
2007 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
2009 if (!orig || !copy) {
2010 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
2016 RegionFactory::add_compound_association (orig, copy);
2023 Session::load_nested_sources (const XMLNode& node)
2026 XMLNodeConstIterator niter;
2028 nlist = node.children();
2030 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2031 if ((*niter)->name() == "Source") {
2033 /* it may already exist, so don't recreate it unnecessarily
2036 XMLProperty const * prop = (*niter)->property (X_("id"));
2038 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2042 ID source_id (prop->value());
2044 if (!source_by_id (source_id)) {
2047 SourceFactory::create (*this, **niter, true);
2049 catch (failed_constructor& err) {
2050 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2057 boost::shared_ptr<Region>
2058 Session::XMLRegionFactory (const XMLNode& node, bool full)
2060 XMLProperty const * type = node.property("type");
2064 const XMLNodeList& nlist = node.children();
2066 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2067 XMLNode *child = (*niter);
2068 if (child->name() == "NestedSource") {
2069 load_nested_sources (*child);
2073 if (!type || type->value() == "audio") {
2074 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2075 } else if (type->value() == "midi") {
2076 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2079 } catch (failed_constructor& err) {
2080 return boost::shared_ptr<Region> ();
2083 return boost::shared_ptr<Region> ();
2086 boost::shared_ptr<AudioRegion>
2087 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2089 XMLProperty const * prop;
2090 boost::shared_ptr<Source> source;
2091 boost::shared_ptr<AudioSource> as;
2093 SourceList master_sources;
2094 uint32_t nchans = 1;
2097 if (node.name() != X_("Region")) {
2098 return boost::shared_ptr<AudioRegion>();
2101 node.get_property (X_("channels"), nchans);
2103 if ((prop = node.property ("name")) == 0) {
2104 cerr << "no name for this region\n";
2108 if ((prop = node.property (X_("source-0"))) == 0) {
2109 if ((prop = node.property ("source")) == 0) {
2110 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2111 return boost::shared_ptr<AudioRegion>();
2115 PBD::ID s_id (prop->value());
2117 if ((source = source_by_id (s_id)) == 0) {
2118 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2119 return boost::shared_ptr<AudioRegion>();
2122 as = boost::dynamic_pointer_cast<AudioSource>(source);
2124 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2125 return boost::shared_ptr<AudioRegion>();
2128 sources.push_back (as);
2130 /* pickup other channels */
2132 for (uint32_t n=1; n < nchans; ++n) {
2133 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2134 if ((prop = node.property (buf)) != 0) {
2136 PBD::ID id2 (prop->value());
2138 if ((source = source_by_id (id2)) == 0) {
2139 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2140 return boost::shared_ptr<AudioRegion>();
2143 as = boost::dynamic_pointer_cast<AudioSource>(source);
2145 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2146 return boost::shared_ptr<AudioRegion>();
2148 sources.push_back (as);
2152 for (uint32_t n = 0; n < nchans; ++n) {
2153 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2154 if ((prop = node.property (buf)) != 0) {
2156 PBD::ID id2 (prop->value());
2158 if ((source = source_by_id (id2)) == 0) {
2159 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2160 return boost::shared_ptr<AudioRegion>();
2163 as = boost::dynamic_pointer_cast<AudioSource>(source);
2165 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2166 return boost::shared_ptr<AudioRegion>();
2168 master_sources.push_back (as);
2173 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2175 /* a final detail: this is the one and only place that we know how long missing files are */
2177 if (region->whole_file()) {
2178 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2179 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2181 sfp->set_length (region->length());
2186 if (!master_sources.empty()) {
2187 if (master_sources.size() != nchans) {
2188 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2190 region->set_master_sources (master_sources);
2198 catch (failed_constructor& err) {
2199 return boost::shared_ptr<AudioRegion>();
2203 boost::shared_ptr<MidiRegion>
2204 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2206 XMLProperty const * prop;
2207 boost::shared_ptr<Source> source;
2208 boost::shared_ptr<MidiSource> ms;
2211 if (node.name() != X_("Region")) {
2212 return boost::shared_ptr<MidiRegion>();
2215 if ((prop = node.property ("name")) == 0) {
2216 cerr << "no name for this region\n";
2220 if ((prop = node.property (X_("source-0"))) == 0) {
2221 if ((prop = node.property ("source")) == 0) {
2222 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2223 return boost::shared_ptr<MidiRegion>();
2227 PBD::ID s_id (prop->value());
2229 if ((source = source_by_id (s_id)) == 0) {
2230 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2231 return boost::shared_ptr<MidiRegion>();
2234 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2236 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2237 return boost::shared_ptr<MidiRegion>();
2240 sources.push_back (ms);
2243 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2244 /* a final detail: this is the one and only place that we know how long missing files are */
2246 if (region->whole_file()) {
2247 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2248 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2250 sfp->set_length (region->length());
2258 catch (failed_constructor& err) {
2259 return boost::shared_ptr<MidiRegion>();
2264 Session::get_sources_as_xml ()
2267 XMLNode* node = new XMLNode (X_("Sources"));
2268 Glib::Threads::Mutex::Lock lm (source_lock);
2270 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2271 node->add_child_nocopy (i->second->get_state());
2278 Session::reset_write_sources (bool mark_write_complete, bool force)
2280 boost::shared_ptr<RouteList> rl = routes.reader();
2281 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2282 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2284 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2285 tr->reset_write_sources(mark_write_complete, force);
2286 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2292 Session::load_sources (const XMLNode& node)
2295 XMLNodeConstIterator niter;
2296 /* don't need this but it stops some
2297 * versions of gcc complaining about
2298 * discarded return values.
2300 boost::shared_ptr<Source> source;
2302 nlist = node.children();
2305 std::map<std::string, std::string> relocation;
2307 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2308 #ifdef PLATFORM_WINDOWS
2312 XMLNode srcnode (**niter);
2313 bool try_replace_abspath = true;
2317 #ifdef PLATFORM_WINDOWS
2318 // do not show "insert media" popups (files embedded from removable media).
2319 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2321 if ((source = XMLSourceFactory (srcnode)) == 0) {
2322 error << _("Session: cannot create Source from XML description.") << endmsg;
2324 #ifdef PLATFORM_WINDOWS
2325 SetErrorMode(old_mode);
2328 } catch (MissingSource& err) {
2329 #ifdef PLATFORM_WINDOWS
2330 SetErrorMode(old_mode);
2333 /* try previous abs path replacements first */
2334 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2335 std::string dir = Glib::path_get_dirname (err.path);
2336 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2337 if (rl != relocation.end ()) {
2338 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2339 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2340 srcnode.set_property ("origin", newpath);
2341 try_replace_abspath = false;
2348 _missing_file_replacement = "";
2350 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2351 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2352 PROGRAM_NAME) << endmsg;
2356 if (!no_questions_about_missing_files) {
2357 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2362 switch (user_choice) {
2364 /* user added a new search location
2365 * or selected a new absolute path,
2367 if (Glib::path_is_absolute (err.path)) {
2368 if (!_missing_file_replacement.empty ()) {
2369 /* replace origin, in XML */
2370 std::string newpath = Glib::build_filename (
2371 _missing_file_replacement, Glib::path_get_basename (err.path));
2372 srcnode.set_property ("origin", newpath);
2373 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2374 _missing_file_replacement = "";
2381 /* user asked to quit the entire session load */
2385 no_questions_about_missing_files = true;
2389 no_questions_about_missing_files = true;
2396 case DataType::AUDIO:
2397 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2400 case DataType::MIDI:
2401 /* The MIDI file is actually missing so
2402 * just create a new one in the same
2403 * location. Do not announce its
2407 if (!Glib::path_is_absolute (err.path)) {
2408 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2410 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2415 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2416 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2417 /* reset ID to match the missing one */
2418 source->set_id (**niter);
2419 /* Now we can announce it */
2420 SourceFactory::SourceCreated (source);
2431 boost::shared_ptr<Source>
2432 Session::XMLSourceFactory (const XMLNode& node)
2434 if (node.name() != "Source") {
2435 return boost::shared_ptr<Source>();
2439 /* note: do peak building in another thread when loading session state */
2440 return SourceFactory::create (*this, node, true);
2443 catch (failed_constructor& err) {
2444 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2445 return boost::shared_ptr<Source>();
2450 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2452 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2456 bool absolute_path = Glib::path_is_absolute (template_name);
2458 /* directory to put the template in */
2459 std::string template_dir_path;
2461 if (!absolute_path) {
2462 std::string user_template_dir(user_template_directory());
2464 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2465 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2466 user_template_dir, g_strerror (errno)) << endmsg;
2470 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2472 template_dir_path = template_name;
2475 if (!ARDOUR::Profile->get_trx()) {
2476 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2477 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2478 template_dir_path) << endmsg;
2482 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2483 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2484 template_dir_path, g_strerror (errno)) << endmsg;
2490 std::string template_file_path;
2492 if (ARDOUR::Profile->get_trx()) {
2493 template_file_path = template_name;
2495 if (absolute_path) {
2496 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2498 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2502 SessionSaveUnderway (); /* EMIT SIGNAL */
2507 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2508 root = &get_template ();
2511 root->remove_nodes_and_delete (X_("description"));
2513 if (!description.empty()) {
2514 XMLNode* desc = new XMLNode (X_("description"));
2515 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2516 desc->add_child_nocopy (*desc_cont);
2518 root->add_child_nocopy (*desc);
2521 tree.set_root (root);
2523 if (!tree.write (template_file_path)) {
2524 error << _("template not saved") << endmsg;
2528 store_recent_templates (template_file_path);
2534 Session::refresh_disk_space ()
2536 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2538 Glib::Threads::Mutex::Lock lm (space_lock);
2540 /* get freespace on every FS that is part of the session path */
2542 _total_free_4k_blocks = 0;
2543 _total_free_4k_blocks_uncertain = false;
2545 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2546 #if defined(__NetBSD__)
2547 struct statvfs statfsbuf;
2549 statvfs (i->path.c_str(), &statfsbuf);
2551 struct statfs statfsbuf;
2553 statfs (i->path.c_str(), &statfsbuf);
2555 double const scale = statfsbuf.f_bsize / 4096.0;
2557 /* See if this filesystem is read-only */
2558 struct statvfs statvfsbuf;
2559 statvfs (i->path.c_str(), &statvfsbuf);
2561 /* f_bavail can be 0 if it is undefined for whatever
2562 filesystem we are looking at; Samba shares mounted
2563 via GVFS are an example of this.
2565 if (statfsbuf.f_bavail == 0) {
2566 /* block count unknown */
2568 i->blocks_unknown = true;
2569 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2570 /* read-only filesystem */
2572 i->blocks_unknown = false;
2574 /* read/write filesystem with known space */
2575 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2576 i->blocks_unknown = false;
2579 _total_free_4k_blocks += i->blocks;
2580 if (i->blocks_unknown) {
2581 _total_free_4k_blocks_uncertain = true;
2584 #elif defined PLATFORM_WINDOWS
2585 vector<string> scanned_volumes;
2586 vector<string>::iterator j;
2587 vector<space_and_path>::iterator i;
2588 DWORD nSectorsPerCluster, nBytesPerSector,
2589 nFreeClusters, nTotalClusters;
2593 _total_free_4k_blocks = 0;
2595 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2596 strncpy (disk_drive, (*i).path.c_str(), 3);
2600 volume_found = false;
2601 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2603 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2604 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2605 i->blocks = (uint32_t)(nFreeBytes / 4096);
2607 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2608 if (0 == j->compare(disk_drive)) {
2609 volume_found = true;
2614 if (!volume_found) {
2615 scanned_volumes.push_back(disk_drive);
2616 _total_free_4k_blocks += i->blocks;
2621 if (0 == _total_free_4k_blocks) {
2622 strncpy (disk_drive, path().c_str(), 3);
2625 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2627 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2628 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2629 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2636 Session::get_best_session_directory_for_new_audio ()
2638 vector<space_and_path>::iterator i;
2639 string result = _session_dir->root_path();
2641 /* handle common case without system calls */
2643 if (session_dirs.size() == 1) {
2647 /* OK, here's the algorithm we're following here:
2649 We want to select which directory to use for
2650 the next file source to be created. Ideally,
2651 we'd like to use a round-robin process so as to
2652 get maximum performance benefits from splitting
2653 the files across multiple disks.
2655 However, in situations without much diskspace, an
2656 RR approach may end up filling up a filesystem
2657 with new files while others still have space.
2658 Its therefore important to pay some attention to
2659 the freespace in the filesystem holding each
2660 directory as well. However, if we did that by
2661 itself, we'd keep creating new files in the file
2662 system with the most space until it was as full
2663 as all others, thus negating any performance
2664 benefits of this RAID-1 like approach.
2666 So, we use a user-configurable space threshold. If
2667 there are at least 2 filesystems with more than this
2668 much space available, we use RR selection between them.
2669 If not, then we pick the filesystem with the most space.
2671 This gets a good balance between the two
2675 refresh_disk_space ();
2677 int free_enough = 0;
2679 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2680 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2685 if (free_enough >= 2) {
2686 /* use RR selection process, ensuring that the one
2690 i = last_rr_session_dir;
2693 if (++i == session_dirs.end()) {
2694 i = session_dirs.begin();
2697 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2698 SessionDirectory sdir(i->path);
2699 if (sdir.create ()) {
2701 last_rr_session_dir = i;
2706 } while (i != last_rr_session_dir);
2710 /* pick FS with the most freespace (and that
2711 seems to actually work ...)
2714 vector<space_and_path> sorted;
2715 space_and_path_ascending_cmp cmp;
2717 sorted = session_dirs;
2718 sort (sorted.begin(), sorted.end(), cmp);
2720 for (i = sorted.begin(); i != sorted.end(); ++i) {
2721 SessionDirectory sdir(i->path);
2722 if (sdir.create ()) {
2724 last_rr_session_dir = i;
2734 Session::automation_dir () const
2736 return Glib::build_filename (_path, automation_dir_name);
2740 Session::analysis_dir () const
2742 return Glib::build_filename (_path, analysis_dir_name);
2746 Session::plugins_dir () const
2748 return Glib::build_filename (_path, plugins_dir_name);
2752 Session::externals_dir () const
2754 return Glib::build_filename (_path, externals_dir_name);
2758 Session::load_bundles (XMLNode const & node)
2760 XMLNodeList nlist = node.children();
2761 XMLNodeConstIterator niter;
2765 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2766 if ((*niter)->name() == "InputBundle") {
2767 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2768 } else if ((*niter)->name() == "OutputBundle") {
2769 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2771 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2780 Session::load_route_groups (const XMLNode& node, int version)
2782 XMLNodeList nlist = node.children();
2783 XMLNodeConstIterator niter;
2787 if (version >= 3000) {
2789 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2790 if ((*niter)->name() == "RouteGroup") {
2791 RouteGroup* rg = new RouteGroup (*this, "");
2792 add_route_group (rg);
2793 rg->set_state (**niter, version);
2797 } else if (version < 3000) {
2799 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2800 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2801 RouteGroup* rg = new RouteGroup (*this, "");
2802 add_route_group (rg);
2803 rg->set_state (**niter, version);
2812 state_file_filter (const string &str, void* /*arg*/)
2814 return (str.length() > strlen(statefile_suffix) &&
2815 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2819 remove_end(string state)
2821 string statename(state);
2823 string::size_type start,end;
2824 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2825 statename = statename.substr (start+1);
2828 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2829 end = statename.length();
2832 return string(statename.substr (0, end));
2836 Session::possible_states (string path)
2838 vector<string> states;
2839 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2841 transform(states.begin(), states.end(), states.begin(), remove_end);
2843 sort (states.begin(), states.end());
2849 Session::possible_states () const
2851 return possible_states(_path);
2855 Session::new_route_group (const std::string& name)
2857 RouteGroup* rg = NULL;
2859 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2860 if ((*i)->name () == name) {
2867 rg = new RouteGroup (*this, name);
2868 add_route_group (rg);
2874 Session::add_route_group (RouteGroup* g)
2876 _route_groups.push_back (g);
2877 route_group_added (g); /* EMIT SIGNAL */
2879 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2880 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2881 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2887 Session::remove_route_group (RouteGroup& rg)
2889 list<RouteGroup*>::iterator i;
2891 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2892 _route_groups.erase (i);
2895 route_group_removed (); /* EMIT SIGNAL */
2899 /** Set a new order for our route groups, without adding or removing any.
2900 * @param groups Route group list in the new order.
2903 Session::reorder_route_groups (list<RouteGroup*> groups)
2905 _route_groups = groups;
2907 route_groups_reordered (); /* EMIT SIGNAL */
2913 Session::route_group_by_name (string name)
2915 list<RouteGroup *>::iterator i;
2917 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2918 if ((*i)->name() == name) {
2926 Session::all_route_group() const
2928 return *_all_route_group;
2932 Session::add_commands (vector<Command*> const & cmds)
2934 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2940 Session::add_command (Command* const cmd)
2942 assert (_current_trans);
2943 DEBUG_UNDO_HISTORY (
2944 string_compose ("Current Undo Transaction %1, adding command: %2",
2945 _current_trans->name (),
2947 _current_trans->add_command (cmd);
2950 PBD::StatefulDiffCommand*
2951 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2953 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2959 Session::begin_reversible_command (const string& name)
2961 begin_reversible_command (g_quark_from_string (name.c_str ()));
2964 /** Begin a reversible command using a GQuark to identify it.
2965 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2966 * but there must be as many begin...()s as there are commit...()s.
2969 Session::begin_reversible_command (GQuark q)
2971 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2972 to hold all the commands that are committed. This keeps the order of
2973 commands correct in the history.
2976 if (_current_trans == 0) {
2977 DEBUG_UNDO_HISTORY (string_compose (
2978 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2980 /* start a new transaction */
2981 assert (_current_trans_quarks.empty ());
2982 _current_trans = new UndoTransaction();
2983 _current_trans->set_name (g_quark_to_string (q));
2985 DEBUG_UNDO_HISTORY (
2986 string_compose ("Begin Reversible Command, current transaction: %1",
2987 _current_trans->name ()));
2990 _current_trans_quarks.push_front (q);
2994 Session::abort_reversible_command ()
2996 if (_current_trans != 0) {
2997 DEBUG_UNDO_HISTORY (
2998 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2999 _current_trans->clear();
3000 delete _current_trans;
3002 _current_trans_quarks.clear();
3007 Session::commit_reversible_command (Command *cmd)
3009 assert (_current_trans);
3010 assert (!_current_trans_quarks.empty ());
3015 DEBUG_UNDO_HISTORY (
3016 string_compose ("Current Undo Transaction %1, adding command: %2",
3017 _current_trans->name (),
3019 _current_trans->add_command (cmd);
3022 DEBUG_UNDO_HISTORY (
3023 string_compose ("Commit Reversible Command, current transaction: %1",
3024 _current_trans->name ()));
3026 _current_trans_quarks.pop_front ();
3028 if (!_current_trans_quarks.empty ()) {
3029 DEBUG_UNDO_HISTORY (
3030 string_compose ("Commit Reversible Command, transaction is not "
3031 "top-level, current transaction: %1",
3032 _current_trans->name ()));
3033 /* the transaction we're committing is not the top-level one */
3037 if (_current_trans->empty()) {
3038 /* no commands were added to the transaction, so just get rid of it */
3039 DEBUG_UNDO_HISTORY (
3040 string_compose ("Commit Reversible Command, No commands were "
3041 "added to current transaction: %1",
3042 _current_trans->name ()));
3043 delete _current_trans;
3048 gettimeofday (&now, 0);
3049 _current_trans->set_timestamp (now);
3051 _history.add (_current_trans);
3056 accept_all_audio_files (const string& path, void* /*arg*/)
3058 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3062 if (!AudioFileSource::safe_audio_file_extension (path)) {
3070 accept_all_midi_files (const string& path, void* /*arg*/)
3072 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3076 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3077 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3078 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3082 accept_all_state_files (const string& path, void* /*arg*/)
3084 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3088 std::string const statefile_ext (statefile_suffix);
3089 if (path.length() >= statefile_ext.length()) {
3090 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3097 Session::find_all_sources (string path, set<string>& result)
3102 if (!tree.read (path)) {
3106 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3111 XMLNodeConstIterator niter;
3113 nlist = node->children();
3117 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3119 XMLProperty const * prop;
3121 if ((prop = (*niter)->property (X_("type"))) == 0) {
3125 DataType type (prop->value());
3127 if ((prop = (*niter)->property (X_("name"))) == 0) {
3131 if (Glib::path_is_absolute (prop->value())) {
3132 /* external file, ignore */
3140 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3141 result.insert (found_path);
3149 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3151 vector<string> state_files;
3153 string this_snapshot_path;
3159 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3160 ripped = ripped.substr (0, ripped.length() - 1);
3163 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3165 if (state_files.empty()) {
3170 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3171 this_snapshot_path += statefile_suffix;
3173 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3175 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3177 if (exclude_this_snapshot && *i == this_snapshot_path) {
3178 cerr << "\texcluded\n";
3183 if (find_all_sources (*i, result) < 0) {
3191 struct RegionCounter {
3192 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3193 AudioSourceList::iterator iter;
3194 boost::shared_ptr<Region> region;
3197 RegionCounter() : count (0) {}
3201 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3203 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3204 return r.get_value_or (1);
3208 Session::cleanup_regions ()
3210 bool removed = false;
3211 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3213 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3215 uint32_t used = playlists->region_use_count (i->second);
3217 if (used == 0 && !i->second->automatic ()) {
3218 boost::weak_ptr<Region> w = i->second;
3221 RegionFactory::map_remove (w);
3228 // re-check to remove parent references of compound regions
3229 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3230 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3234 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3235 if (0 == playlists->region_use_count (i->second)) {
3236 boost::weak_ptr<Region> w = i->second;
3238 RegionFactory::map_remove (w);
3245 /* dump the history list */
3252 Session::can_cleanup_peakfiles () const
3254 if (deletion_in_progress()) {
3257 if (!_writable || (_state_of_the_state & CannotSave)) {
3258 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3261 if (record_status() == Recording) {
3262 error << _("Cannot cleanup peak-files while recording") << endmsg;
3269 Session::cleanup_peakfiles ()
3271 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3276 assert (can_cleanup_peakfiles ());
3277 assert (!peaks_cleanup_in_progres());
3279 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3281 int timeout = 5000; // 5 seconds
3282 while (!SourceFactory::files_with_peaks.empty()) {
3283 Glib::usleep (1000);
3284 if (--timeout < 0) {
3285 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3286 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3291 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3292 boost::shared_ptr<AudioSource> as;
3293 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3294 as->close_peakfile();
3298 PBD::clear_directory (session_directory().peak_path());
3300 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3302 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3303 boost::shared_ptr<AudioSource> as;
3304 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3305 SourceFactory::setup_peakfile(as, true);
3312 Session::cleanup_sources (CleanupReport& rep)
3314 // FIXME: needs adaptation to midi
3316 vector<boost::shared_ptr<Source> > dead_sources;
3319 vector<string> candidates;
3320 vector<string> unused;
3321 set<string> sources_used_by_all_snapshots;
3328 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3330 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3332 /* this is mostly for windows which doesn't allow file
3333 * renaming if the file is in use. But we don't special
3334 * case it because we need to know if this causes
3335 * problems, and the easiest way to notice that is to
3336 * keep it in place for all platforms.
3339 request_stop (false);
3341 _butler->wait_until_finished ();
3343 /* consider deleting all unused playlists */
3345 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3350 /* sync the "all regions" property of each playlist with its current state */
3352 playlists->sync_all_regions_with_regions ();
3354 /* find all un-used sources */
3359 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3361 SourceMap::iterator tmp;
3366 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3370 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3371 dead_sources.push_back (i->second);
3372 i->second->drop_references ();
3378 /* build a list of all the possible audio directories for the session */
3380 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3381 SessionDirectory sdir ((*i).path);
3382 asp += sdir.sound_path();
3384 audio_path += asp.to_string();
3387 /* build a list of all the possible midi directories for the session */
3389 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3390 SessionDirectory sdir ((*i).path);
3391 msp += sdir.midi_path();
3393 midi_path += msp.to_string();
3395 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3396 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3398 /* add sources from all other snapshots as "used", but don't use this
3399 snapshot because the state file on disk still references sources we
3400 may have already dropped.
3403 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3405 /* Although the region factory has a list of all regions ever created
3406 * for this session, we're only interested in regions actually in
3407 * playlists right now. So merge all playlist regions lists together.
3409 * This will include the playlists used within compound regions.
3412 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3414 /* add our current source list
3417 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3418 boost::shared_ptr<FileSource> fs;
3419 SourceMap::iterator tmp = i;
3422 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3428 /* this is mostly for windows which doesn't allow file
3429 * renaming if the file is in use. But we do not special
3430 * case it because we need to know if this causes
3431 * problems, and the easiest way to notice that is to
3432 * keep it in place for all platforms.
3437 if (!fs->is_stub()) {
3439 /* Note that we're checking a list of all
3440 * sources across all snapshots with the list
3441 * of sources used by this snapshot.
3444 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3445 /* this source is in use by this snapshot */
3446 sources_used_by_all_snapshots.insert (fs->path());
3447 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3449 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3450 /* this source is NOT in use by this snapshot */
3452 /* remove all related regions from RegionFactory master list */
3454 RegionFactory::remove_regions_using_source (i->second);
3456 /* remove from our current source list
3457 * also. We may not remove it from
3458 * disk, because it may be used by
3459 * other snapshots, but it isn't used inside this
3460 * snapshot anymore, so we don't need a
3471 /* now check each candidate source to see if it exists in the list of
3472 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3475 cerr << "Candidates: " << candidates.size() << endl;
3476 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3478 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3483 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3485 tmppath1 = canonical_path (spath);
3486 tmppath2 = canonical_path ((*i));
3488 cerr << "\t => " << tmppath2 << endl;
3490 if (tmppath1 == tmppath2) {
3497 unused.push_back (spath);
3501 cerr << "Actually unused: " << unused.size() << endl;
3503 if (unused.empty()) {
3509 /* now try to move all unused files into the "dead" directory(ies) */
3511 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3516 /* don't move the file across filesystems, just
3517 * stick it in the `dead_dir_name' directory
3518 * on whichever filesystem it was already on.
3521 if ((*x).find ("/sounds/") != string::npos) {
3523 /* old school, go up 1 level */
3525 newpath = Glib::path_get_dirname (*x); // "sounds"
3526 newpath = Glib::path_get_dirname (newpath); // "session-name"
3530 /* new school, go up 4 levels */
3532 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3533 newpath = Glib::path_get_dirname (newpath); // "session-name"
3534 newpath = Glib::path_get_dirname (newpath); // "interchange"
3535 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3538 newpath = Glib::build_filename (newpath, dead_dir_name);
3540 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3541 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3545 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3547 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3549 /* the new path already exists, try versioning */
3551 char buf[PATH_MAX+1];
3555 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3558 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3559 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3563 if (version == 999) {
3564 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3568 newpath = newpath_v;
3573 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3574 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3575 newpath, g_strerror (errno)) << endmsg;
3579 /* see if there an easy to find peakfile for this file, and remove it. */
3581 string base = Glib::path_get_basename (*x);
3582 base += "%A"; /* this is what we add for the channel suffix of all native files,
3583 * or for the first channel of embedded files. it will miss
3584 * some peakfiles for other channels
3586 string peakpath = construct_peak_filepath (base);
3588 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3589 if (::g_unlink (peakpath.c_str ()) != 0) {
3590 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3591 g_strerror (errno)) << endmsg;
3592 /* try to back out */
3593 ::g_rename (newpath.c_str (), _path.c_str ());
3598 rep.paths.push_back (*x);
3599 rep.space += statbuf.st_size;
3602 /* dump the history list */
3606 /* save state so we don't end up a session file
3607 * referring to non-existent sources.
3614 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3620 Session::cleanup_trash_sources (CleanupReport& rep)
3622 // FIXME: needs adaptation for MIDI
3624 vector<space_and_path>::iterator i;
3630 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3632 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3634 clear_directory (dead_dir, &rep.space, &rep.paths);
3641 Session::set_dirty ()
3643 /* return early if there's nothing to do */
3648 /* never mark session dirty during loading */
3649 if (_state_of_the_state & Loading) {
3653 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3654 DirtyChanged(); /* EMIT SIGNAL */
3658 Session::set_clean ()
3660 bool was_dirty = dirty();
3662 _state_of_the_state = Clean;
3665 DirtyChanged(); /* EMIT SIGNAL */
3670 Session::set_deletion_in_progress ()
3672 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3676 Session::clear_deletion_in_progress ()
3678 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3682 Session::add_controllable (boost::shared_ptr<Controllable> c)
3684 /* this adds a controllable to the list managed by the Session.
3685 this is a subset of those managed by the Controllable class
3686 itself, and represents the only ones whose state will be saved
3687 as part of the session.
3690 Glib::Threads::Mutex::Lock lm (controllables_lock);
3691 controllables.insert (c);
3694 struct null_deleter { void operator()(void const *) const {} };
3697 Session::remove_controllable (Controllable* c)
3699 if (_state_of_the_state & Deletion) {
3703 Glib::Threads::Mutex::Lock lm (controllables_lock);
3705 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3707 if (x != controllables.end()) {
3708 controllables.erase (x);
3712 boost::shared_ptr<Controllable>
3713 Session::controllable_by_id (const PBD::ID& id)
3715 Glib::Threads::Mutex::Lock lm (controllables_lock);
3717 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3718 if ((*i)->id() == id) {
3723 return boost::shared_ptr<Controllable>();
3726 boost::shared_ptr<AutomationControl>
3727 Session::automation_control_by_id (const PBD::ID& id)
3729 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3733 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3736 Stateful::add_instant_xml (node, _path);
3739 if (write_to_config) {
3740 Config->add_instant_xml (node);
3745 Session::instant_xml (const string& node_name)
3747 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3748 if (get_disable_all_loaded_plugins ()) {
3752 return Stateful::instant_xml (node_name, _path);
3756 Session::save_history (string snapshot_name)
3764 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3765 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3769 if (snapshot_name.empty()) {
3770 snapshot_name = _current_snapshot_name;
3773 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3774 const string backup_filename = history_filename + backup_suffix;
3775 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3776 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3778 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3779 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3780 error << _("could not backup old history file, current history not saved") << endmsg;
3785 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3787 if (!tree.write (xml_path))
3789 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3791 if (g_remove (xml_path.c_str()) != 0) {
3792 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3793 xml_path, g_strerror (errno)) << endmsg;
3795 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3796 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3797 backup_path, g_strerror (errno)) << endmsg;
3807 Session::restore_history (string snapshot_name)
3811 if (snapshot_name.empty()) {
3812 snapshot_name = _current_snapshot_name;
3815 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3816 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3818 info << "Loading history from " << xml_path << endmsg;
3820 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3821 info << string_compose (_("%1: no history file \"%2\" for this session."),
3822 _name, xml_path) << endmsg;
3826 if (!tree.read (xml_path)) {
3827 error << string_compose (_("Could not understand session history file \"%1\""),
3828 xml_path) << endmsg;
3835 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3843 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3844 !t->get_property ("tv-usec", tv_usec)) {
3848 UndoTransaction* ut = new UndoTransaction ();
3849 ut->set_name (name);
3853 tv.tv_usec = tv_usec;
3854 ut->set_timestamp(tv);
3856 for (XMLNodeConstIterator child_it = t->children().begin();
3857 child_it != t->children().end(); child_it++)
3859 XMLNode *n = *child_it;
3862 if (n->name() == "MementoCommand" ||
3863 n->name() == "MementoUndoCommand" ||
3864 n->name() == "MementoRedoCommand") {
3866 if ((c = memento_command_factory(n))) {
3870 } else if (n->name() == "NoteDiffCommand") {
3871 PBD::ID id (n->property("midi-source")->value());
3872 boost::shared_ptr<MidiSource> midi_source =
3873 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3875 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3877 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3880 } else if (n->name() == "SysExDiffCommand") {
3882 PBD::ID id (n->property("midi-source")->value());
3883 boost::shared_ptr<MidiSource> midi_source =
3884 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3886 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3888 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3891 } else if (n->name() == "PatchChangeDiffCommand") {
3893 PBD::ID id (n->property("midi-source")->value());
3894 boost::shared_ptr<MidiSource> midi_source =
3895 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3897 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3899 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3902 } else if (n->name() == "StatefulDiffCommand") {
3903 if ((c = stateful_diff_command_factory (n))) {
3904 ut->add_command (c);
3907 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3918 Session::config_changed (std::string p, bool ours)
3924 if (p == "auto-loop") {
3926 } else if (p == "session-monitoring") {
3928 } else if (p == "auto-input") {
3930 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3931 /* auto-input only makes a difference if we're rolling */
3932 set_track_monitor_input_status (!config.get_auto_input());
3935 } else if (p == "punch-in") {
3939 if ((location = _locations->auto_punch_location()) != 0) {
3941 if (config.get_punch_in ()) {
3942 auto_punch_start_changed (location);
3944 clear_events (SessionEvent::PunchIn);
3948 } else if (p == "punch-out") {
3952 if ((location = _locations->auto_punch_location()) != 0) {
3954 if (config.get_punch_out()) {
3955 auto_punch_end_changed (location);
3957 clear_events (SessionEvent::PunchOut);
3961 } else if (p == "edit-mode") {
3963 Glib::Threads::Mutex::Lock lm (playlists->lock);
3965 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3966 (*i)->set_edit_mode (Config->get_edit_mode ());
3969 } else if (p == "use-video-sync") {
3971 waiting_for_sync_offset = config.get_use_video_sync();
3973 } else if (p == "mmc-control") {
3975 //poke_midi_thread ();
3977 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3979 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3981 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3983 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3985 } else if (p == "midi-control") {
3987 //poke_midi_thread ();
3989 } else if (p == "raid-path") {
3991 setup_raid_path (config.get_raid_path());
3993 } else if (p == "timecode-format") {
3997 } else if (p == "video-pullup") {
4001 } else if (p == "seamless-loop") {
4003 if (play_loop && transport_rolling()) {
4004 // to reset diskstreams etc
4005 request_play_loop (true);
4008 } else if (p == "rf-speed") {
4010 cumulative_rf_motion = 0;
4013 } else if (p == "click-sound") {
4015 setup_click_sounds (1);
4017 } else if (p == "click-emphasis-sound") {
4019 setup_click_sounds (-1);
4021 } else if (p == "clicking") {
4023 if (Config->get_clicking()) {
4024 if (_click_io && click_data) { // don't require emphasis data
4031 } else if (p == "click-record-only") {
4033 _click_rec_only = Config->get_click_record_only();
4035 } else if (p == "click-gain") {
4038 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4041 } else if (p == "send-mtc") {
4043 if (Config->get_send_mtc ()) {
4044 /* mark us ready to send */
4045 next_quarter_frame_to_send = 0;
4048 } else if (p == "send-mmc") {
4050 _mmc->enable_send (Config->get_send_mmc ());
4051 if (Config->get_send_mmc ()) {
4052 /* re-initialize MMC */
4053 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4054 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4057 } else if (p == "jack-time-master") {
4059 engine().reset_timebase ();
4061 } else if (p == "native-file-header-format") {
4063 if (!first_file_header_format_reset) {
4064 reset_native_file_format ();
4067 first_file_header_format_reset = false;
4069 } else if (p == "native-file-data-format") {
4071 if (!first_file_data_format_reset) {
4072 reset_native_file_format ();
4075 first_file_data_format_reset = false;
4077 } else if (p == "external-sync") {
4078 if (!config.get_external_sync()) {
4079 drop_sync_source ();
4081 switch_to_sync_source (Config->get_sync_source());
4083 } else if (p == "denormal-model") {
4085 } else if (p == "history-depth") {
4086 set_history_depth (Config->get_history_depth());
4087 } else if (p == "remote-model") {
4088 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4091 } else if (p == "initial-program-change") {
4093 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4096 buf[0] = MIDI::program; // channel zero by default
4097 buf[1] = (Config->get_initial_program_change() & 0x7f);
4099 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4101 } else if (p == "solo-mute-override") {
4102 // catch_up_on_solo_mute_override ();
4103 } else if (p == "listen-position" || p == "pfl-position") {
4104 listen_position_changed ();
4105 } else if (p == "solo-control-is-listen-control") {
4106 solo_control_mode_changed ();
4107 } else if (p == "solo-mute-gain") {
4108 _solo_cut_control->Changed (true, Controllable::NoGroup);
4109 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4110 last_timecode_valid = false;
4111 } else if (p == "playback-buffer-seconds") {
4112 AudioSource::allocate_working_buffers (sample_rate());
4113 } else if (p == "ltc-source-port") {
4114 reconnect_ltc_input ();
4115 } else if (p == "ltc-sink-port") {
4116 reconnect_ltc_output ();
4117 } else if (p == "timecode-generator-offset") {
4118 ltc_tx_parse_offset();
4119 } else if (p == "auto-return-target-list") {
4120 follow_playhead_priority ();
4127 Session::set_history_depth (uint32_t d)
4129 _history.set_depth (d);
4132 /** Connect things to the MMC object */
4134 Session::setup_midi_machine_control ()
4136 _mmc = new MIDI::MachineControl;
4138 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4139 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4141 if (!async_out || !async_out) {
4145 /* XXXX argh, passing raw pointers back into libmidi++ */
4147 MIDI::Port* mmc_in = async_in.get();
4148 MIDI::Port* mmc_out = async_out.get();
4150 _mmc->set_ports (mmc_in, mmc_out);
4152 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4153 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4154 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4155 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4156 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4157 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4158 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4159 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4160 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4161 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4162 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4163 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4164 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4166 /* also handle MIDI SPP because its so common */
4168 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4169 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4170 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4173 boost::shared_ptr<Controllable>
4174 Session::solo_cut_control() const
4176 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4177 * controls in Ardour that currently get presented to the user in the GUI that require
4178 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4180 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4181 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4184 return _solo_cut_control;
4188 Session::save_snapshot_name (const std::string & n)
4190 /* assure Stateful::_instant_xml is loaded
4191 * add_instant_xml() only adds to existing data and defaults
4192 * to use an empty Tree otherwise
4194 instant_xml ("LastUsedSnapshot");
4196 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4197 last_used_snapshot->set_property ("name", n);
4198 add_instant_xml (*last_used_snapshot, false);
4202 Session::set_snapshot_name (const std::string & n)
4204 _current_snapshot_name = n;
4205 save_snapshot_name (n);
4209 Session::rename (const std::string& new_name)
4211 string legal_name = legalize_for_path (new_name);
4217 string const old_sources_root = _session_dir->sources_root();
4219 if (!_writable || (_state_of_the_state & CannotSave)) {
4220 error << _("Cannot rename read-only session.") << endmsg;
4221 return 0; // don't show "messed up" warning
4223 if (record_status() == Recording) {
4224 error << _("Cannot rename session while recording") << endmsg;
4225 return 0; // don't show "messed up" warning
4228 StateProtector stp (this);
4233 * interchange subdirectory
4237 * Backup files are left unchanged and not renamed.
4240 /* Windows requires that we close all files before attempting the
4241 * rename. This works on other platforms, but isn't necessary there.
4242 * Leave it in place for all platforms though, since it may help
4243 * catch issues that could arise if the way Source files work ever
4244 * change (since most developers are not using Windows).
4247 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4248 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4254 /* pass one: not 100% safe check that the new directory names don't
4258 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4262 /* this is a stupid hack because Glib::path_get_dirname() is
4263 * lexical-only, and so passing it /a/b/c/ gives a different
4264 * result than passing it /a/b/c ...
4267 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4268 oldstr = oldstr.substr (0, oldstr.length() - 1);
4271 string base = Glib::path_get_dirname (oldstr);
4273 newstr = Glib::build_filename (base, legal_name);
4275 cerr << "Looking for " << newstr << endl;
4277 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4278 cerr << " exists\n";
4287 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4293 /* this is a stupid hack because Glib::path_get_dirname() is
4294 * lexical-only, and so passing it /a/b/c/ gives a different
4295 * result than passing it /a/b/c ...
4298 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4299 oldstr = oldstr.substr (0, oldstr.length() - 1);
4302 string base = Glib::path_get_dirname (oldstr);
4303 newstr = Glib::build_filename (base, legal_name);
4305 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4307 cerr << "Rename " << oldstr << " => " << newstr << endl;
4308 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4309 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4310 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4314 /* Reset path in "session dirs" */
4319 /* reset primary SessionDirectory object */
4322 (*_session_dir) = newstr;
4327 /* now rename directory below session_dir/interchange */
4329 string old_interchange_dir;
4330 string new_interchange_dir;
4332 /* use newstr here because we renamed the path
4333 * (folder/directory) that used to be oldstr to newstr above
4336 v.push_back (newstr);
4337 v.push_back (interchange_dir_name);
4338 v.push_back (Glib::path_get_basename (oldstr));
4340 old_interchange_dir = Glib::build_filename (v);
4343 v.push_back (newstr);
4344 v.push_back (interchange_dir_name);
4345 v.push_back (legal_name);
4347 new_interchange_dir = Glib::build_filename (v);
4349 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4351 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4352 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4353 old_interchange_dir, new_interchange_dir,
4356 error << string_compose (_("renaming %s as %2 failed (%3)"),
4357 old_interchange_dir, new_interchange_dir,
4366 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4367 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4369 cerr << "Rename " << oldstr << " => " << newstr << endl;
4371 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4372 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4373 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4379 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4381 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4382 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4384 cerr << "Rename " << oldstr << " => " << newstr << endl;
4386 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4387 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4388 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4393 /* remove old name from recent sessions */
4394 remove_recent_sessions (_path);
4397 /* update file source paths */
4399 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4400 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4402 string p = fs->path ();
4403 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4405 SourceFactory::setup_peakfile(i->second, true);
4409 set_snapshot_name (new_name);
4414 /* save state again to get everything just right */
4416 save_state (_current_snapshot_name);
4418 /* add to recent sessions */
4420 store_recent_sessions (new_name, _path);
4426 Session::parse_stateful_loading_version (const std::string& version)
4428 if (version.empty ()) {
4429 /* no version implies very old version of Ardour */
4433 if (version.find ('.') != string::npos) {
4434 /* old school version format */
4435 if (version[0] == '2') {
4441 return string_to<int32_t>(version);
4446 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4448 bool found_sr = false;
4449 bool found_data_format = false;
4450 std::string version;
4451 program_version = "";
4453 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4457 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4461 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4464 xmlFreeParserCtxt(ctxt);
4468 xmlNodePtr node = xmlDocGetRootElement(doc);
4471 xmlFreeParserCtxt(ctxt);
4476 /* sample rate & version*/
4479 for (attr = node->properties; attr; attr = attr->next) {
4480 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4481 version = std::string ((char*)attr->children->content);
4483 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4484 sample_rate = atoi ((char*)attr->children->content);
4489 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4493 node = node->children;
4494 while (node != NULL) {
4495 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4496 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4498 program_version = string ((const char*)val);
4499 size_t sep = program_version.find_first_of("-");
4500 if (sep != string::npos) {
4501 program_version = program_version.substr (0, sep);
4506 if (strcmp((const char*) node->name, "Config")) {
4510 for (node = node->children; node; node = node->next) {
4511 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4512 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4514 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4517 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4519 found_data_format = true;
4520 } catch (PBD::unknown_enumeration& e) {}
4530 xmlFreeParserCtxt(ctxt);
4533 return (found_sr && found_data_format) ? 0 : 1;
4537 Session::get_snapshot_from_instant (const std::string& session_dir)
4539 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4541 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4546 if (!tree.read (instant_xml_path)) {
4550 XMLProperty const * prop;
4551 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4552 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4553 return prop->value();
4559 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4560 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4563 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4567 SourcePathMap source_path_map;
4569 boost::shared_ptr<AudioFileSource> afs;
4574 Glib::Threads::Mutex::Lock lm (source_lock);
4576 cerr << " total sources = " << sources.size();
4578 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4579 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4585 if (fs->within_session()) {
4589 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4590 source_path_map[fs->path()].push_back (fs);
4592 SeveralFileSources v;
4594 source_path_map.insert (make_pair (fs->path(), v));
4600 cerr << " fsources = " << total << endl;
4602 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4604 /* tell caller where we are */
4606 string old_path = i->first;
4608 callback (n, total, old_path);
4610 cerr << old_path << endl;
4614 switch (i->second.front()->type()) {
4615 case DataType::AUDIO:
4616 new_path = new_audio_source_path_for_embedded (old_path);
4619 case DataType::MIDI:
4620 /* XXX not implemented yet */
4624 if (new_path.empty()) {
4628 cerr << "Move " << old_path << " => " << new_path << endl;
4630 if (!copy_file (old_path, new_path)) {
4631 cerr << "failed !\n";
4635 /* make sure we stop looking in the external
4636 dir/folder. Remember, this is an all-or-nothing
4637 operations, it doesn't merge just some files.
4639 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4641 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4642 (*f)->set_path (new_path);
4647 save_state ("", false, false);
4653 bool accept_all_files (string const &, void *)
4659 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4661 /* 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.
4666 make_new_media_path (string old_path, string new_session_folder, string new_session_name)
4668 // old_path must be in within_session ()
4669 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4671 v.push_back (new_session_folder); /* full path */
4672 v.push_back (interchange_dir_name);
4673 v.push_back (new_session_name); /* just one directory/folder */
4674 v.push_back (typedir);
4675 v.push_back (Glib::path_get_basename (old_path));
4677 return Glib::build_filename (v);
4681 make_new_audio_path (string filename, string new_session_folder, string new_session_name)
4684 v.push_back (new_session_folder); /* full path */
4685 v.push_back (interchange_dir_name);
4686 v.push_back (new_session_name);
4687 v.push_back (ARDOUR::sound_dir_name);
4688 v.push_back (filename);
4690 return Glib::build_filename (v);
4694 Session::save_as (SaveAs& saveas)
4696 vector<string> files;
4697 string current_folder = Glib::path_get_dirname (_path);
4698 string new_folder = legalize_for_path (saveas.new_name);
4699 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4700 int64_t total_bytes = 0;
4704 int32_t internal_file_cnt = 0;
4706 vector<string> do_not_copy_extensions;
4707 do_not_copy_extensions.push_back (statefile_suffix);
4708 do_not_copy_extensions.push_back (pending_suffix);
4709 do_not_copy_extensions.push_back (backup_suffix);
4710 do_not_copy_extensions.push_back (temp_suffix);
4711 do_not_copy_extensions.push_back (history_suffix);
4713 /* get total size */
4715 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4717 /* need to clear this because
4718 * find_files_matching_filter() is cumulative
4723 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4725 all += files.size();
4727 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4729 g_stat ((*i).c_str(), &gsb);
4730 total_bytes += gsb.st_size;
4734 /* save old values so we can switch back if we are not switching to the new session */
4736 string old_path = _path;
4737 string old_name = _name;
4738 string old_snapshot = _current_snapshot_name;
4739 string old_sd = _session_dir->root_path();
4740 vector<string> old_search_path[DataType::num_types];
4741 string old_config_search_path[DataType::num_types];
4743 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4744 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4745 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4746 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4748 /* switch session directory */
4750 (*_session_dir) = to_dir;
4752 /* create new tree */
4754 if (!_session_dir->create()) {
4755 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4760 /* copy all relevant files. Find each location in session_dirs,
4761 * and copy files from there to target.
4764 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4766 /* need to clear this because
4767 * find_files_matching_filter() is cumulative
4772 const size_t prefix_len = (*sd).path.size();
4774 /* Work just on the files within this session dir */
4776 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4778 /* add dir separator to protect against collisions with
4779 * track names (e.g. track named "audiofiles" or
4783 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4784 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4785 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4787 /* copy all the files. Handling is different for media files
4788 than others because of the *silly* subtree we have below the interchange
4789 folder. That really was a bad idea, but I'm not fixing it as part of
4790 implementing ::save_as().
4793 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4795 std::string from = *i;
4798 string filename = Glib::path_get_basename (from);
4799 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4800 if (filename == ".DS_STORE") {
4805 if (from.find (audiofile_dir_string) != string::npos) {
4807 /* audio file: only copy if asked */
4809 if (saveas.include_media && saveas.copy_media) {
4811 string to = make_new_media_path (*i, to_dir, new_folder);
4813 info << "media file copying from " << from << " to " << to << endmsg;
4815 if (!copy_file (from, to)) {
4816 throw Glib::FileError (Glib::FileError::IO_ERROR,
4817 string_compose(_("\ncopying \"%1\" failed !"), from));
4821 /* we found media files inside the session folder */
4823 internal_file_cnt++;
4825 } else if (from.find (midifile_dir_string) != string::npos) {
4827 /* midi file: always copy unless
4828 * creating an empty new session
4831 if (saveas.include_media) {
4833 string to = make_new_media_path (*i, to_dir, new_folder);
4835 info << "media file copying from " << from << " to " << to << endmsg;
4837 if (!copy_file (from, to)) {
4838 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4842 /* we found media files inside the session folder */
4844 internal_file_cnt++;
4846 } else if (from.find (analysis_dir_string) != string::npos) {
4848 /* make sure analysis dir exists in
4849 * new session folder, but we're not
4850 * copying analysis files here, see
4854 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4859 /* normal non-media file. Don't copy state, history, etc.
4862 bool do_copy = true;
4864 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4865 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4866 /* end of filename matches extension, do not copy file */
4872 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4873 /* don't copy peakfiles if
4874 * we're not copying media
4880 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4882 info << "attempting to make directory/folder " << to << endmsg;
4884 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4885 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4888 info << "attempting to copy " << from << " to " << to << endmsg;
4890 if (!copy_file (from, to)) {
4891 throw Glib::FileError (Glib::FileError::IO_ERROR,
4892 string_compose(_("\ncopying \"%1\" failed !"), from));
4897 /* measure file size even if we're not going to copy so that our Progress
4898 signals are correct, since we included these do-not-copy files
4899 in the computation of the total size and file count.
4903 g_stat (from.c_str(), &gsb);
4904 copied += gsb.st_size;
4907 double fraction = (double) copied / total_bytes;
4909 bool keep_going = true;
4911 if (saveas.copy_media) {
4913 /* no need or expectation of this if
4914 * media is not being copied, because
4915 * it will be fast(ish).
4918 /* tell someone "X percent, file M of N"; M is one-based */
4920 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4928 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4934 /* copy optional folders, if any */
4936 string old = plugins_dir ();
4937 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4938 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4939 copy_files (old, newdir);
4942 old = externals_dir ();
4943 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4944 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4945 copy_files (old, newdir);
4948 old = automation_dir ();
4949 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4950 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4951 copy_files (old, newdir);
4954 if (saveas.include_media) {
4956 if (saveas.copy_media) {
4957 #ifndef PLATFORM_WINDOWS
4958 /* There are problems with analysis files on
4959 * Windows, because they used a colon in their
4960 * names as late as 4.0. Colons are not legal
4961 * under Windows even if NTFS allows them.
4963 * This is a tricky problem to solve so for
4964 * just don't copy these files. They will be
4965 * regenerated as-needed anyway, subject to the
4966 * existing issue that the filenames will be
4967 * rejected by Windows, which is a separate
4968 * problem (though related).
4971 /* only needed if we are copying media, since the
4972 * analysis data refers to media data
4975 old = analysis_dir ();
4976 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4977 string newdir = Glib::build_filename (to_dir, "analysis");
4978 copy_files (old, newdir);
4980 #endif /* PLATFORM_WINDOWS */
4985 set_snapshot_name (saveas.new_name);
4986 _name = saveas.new_name;
4988 if (saveas.include_media && !saveas.copy_media) {
4990 /* reset search paths of the new session (which we're pretending to be right now) to
4991 include the original session search path, so we can still find all audio.
4994 if (internal_file_cnt) {
4995 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4996 ensure_search_path_includes (*s, DataType::AUDIO);
4997 cerr << "be sure to include " << *s << " for audio" << endl;
5000 /* we do not do this for MIDI because we copy
5001 all MIDI files if saveas.include_media is
5007 bool was_dirty = dirty ();
5009 save_default_options ();
5011 if (saveas.copy_media && saveas.copy_external) {
5012 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5013 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5017 saveas.final_session_folder_name = _path;
5019 store_recent_sessions (_name, _path);
5021 if (!saveas.switch_to) {
5023 /* save the new state */
5025 save_state ("", false, false, !saveas.include_media);
5027 /* switch back to the way things were */
5031 set_snapshot_name (old_snapshot);
5033 (*_session_dir) = old_sd;
5039 if (internal_file_cnt) {
5040 /* reset these to their original values */
5041 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5042 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5047 /* prune session dirs, and update disk space statistics
5052 session_dirs.clear ();
5053 session_dirs.push_back (sp);
5054 refresh_disk_space ();
5056 _writable = exists_and_writable (_path);
5058 /* ensure that all existing tracks reset their current capture source paths
5060 reset_write_sources (true, true);
5062 /* creating new write sources marks the session as
5063 dirty. If the new session is empty, then
5064 save_state() thinks we're saving a template and will
5065 not mark the session as clean. So do that here,
5066 before we save state.
5069 if (!saveas.include_media) {
5070 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5073 save_state ("", false, false, !saveas.include_media);
5075 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5076 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5079 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5080 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5086 if (fs->within_session()) {
5087 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5088 fs->set_path (newpath);
5093 } catch (Glib::FileError& e) {
5095 saveas.failure_message = e.what();
5097 /* recursively remove all the directories */
5099 remove_directory (to_dir);
5107 saveas.failure_message = _("unknown reason");
5109 /* recursively remove all the directories */
5111 remove_directory (to_dir);
5121 static void set_progress (Progress* p, size_t n, size_t t)
5123 p->set_progress (float (n) / float(t));
5127 Session::archive_session (const std::string& dest,
5128 const std::string& name,
5129 ArchiveEncode compress_audio,
5130 FileArchive::CompressionLevel compression_level,
5131 bool only_used_sources,
5134 if (dest.empty () || name.empty ()) {
5138 /* We are going to temporarily change some source properties,
5139 * don't allow any concurrent saves (periodic or otherwise */
5140 Glib::Threads::Mutex::Lock lm (save_source_lock);
5142 disable_record (false);
5144 /* save current values */
5145 string old_path = _path;
5146 string old_name = _name;
5147 string old_snapshot = _current_snapshot_name;
5148 string old_sd = _session_dir->root_path();
5149 string old_config_search_path[DataType::num_types];
5150 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5151 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5153 /* ensure that session-path is included in search-path */
5155 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5156 if ((*sd).path == old_path) {
5164 /* create temporary dir to save session to */
5165 #ifdef PLATFORM_WINDOWS
5166 char tmp[256] = "C:\\TEMP\\";
5167 GetTempPath (sizeof (tmp), tmp);
5169 char const* tmp = getenv("TMPDIR");
5174 if ((strlen (tmp) + 21) > 1024) {
5179 strcpy (tmptpl, tmp);
5180 strcat (tmptpl, "ardourarchive-XXXXXX");
5181 char* tmpdir = g_mkdtemp (tmptpl);
5187 std::string to_dir = std::string (tmpdir);
5189 /* switch session directory temporarily */
5190 (*_session_dir) = to_dir;
5192 if (!_session_dir->create()) {
5193 (*_session_dir) = old_sd;
5194 remove_directory (to_dir);
5198 /* prepare archive */
5199 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5201 PBD::ScopedConnectionList progress_connection;
5202 PBD::FileArchive ar (archive);
5204 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5207 /* collect files to archive */
5208 std::map<string,string> filemap;
5210 vector<string> do_not_copy_extensions;
5211 do_not_copy_extensions.push_back (statefile_suffix);
5212 do_not_copy_extensions.push_back (pending_suffix);
5213 do_not_copy_extensions.push_back (backup_suffix);
5214 do_not_copy_extensions.push_back (temp_suffix);
5215 do_not_copy_extensions.push_back (history_suffix);
5217 vector<string> blacklist_dirs;
5218 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5219 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5220 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5221 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5222 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5223 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5225 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5226 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_origin;
5227 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5229 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5230 if (only_used_sources) {
5231 playlists->sync_all_regions_with_regions ();
5232 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5235 /* collect audio sources for this session, calc total size for encoding
5236 * add option to only include *used* sources (see Session::cleanup_sources)
5238 size_t total_size = 0;
5240 Glib::Threads::Mutex::Lock lm (source_lock);
5242 /* build a list of used names */
5243 std::set<std::string> audio_file_names;
5244 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5245 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5246 if (!afs || afs->readable_length () == 0) {
5249 if (only_used_sources) {
5253 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5257 audio_file_names.insert (Glib::path_get_basename (afs->path()));
5260 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5261 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5262 if (!afs || afs->readable_length () == 0) {
5266 if (only_used_sources) {
5270 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5275 std::string from = afs->path();
5277 if (compress_audio != NO_ENCODE) {
5278 total_size += afs->readable_length ();
5280 /* copy files as-is */
5281 if (!afs->within_session()) {
5282 string to = Glib::path_get_basename (from);
5284 /* avoid name collitions, see also new_audio_source_path_for_embedded ()
5285 * - avoid conflict with files existing in interchange
5286 * - avoid conflict with other embedded sources
5288 if (audio_file_names.find (to) == audio_file_names.end ()) {
5289 // we need a new name, add a '-<num>' before the '.<ext>'
5290 string bn = to.substr (0, to.find_last_of ('.'));
5291 string ext = to.find_last_of ('.') == string::npos ? "" : to.substr (to.find_last_of ('.'));
5292 to = bn + "-1" + ext;
5294 while (audio_file_names.find (to) == audio_file_names.end ()) {
5295 to = bump_name_once (to, '-');
5298 audio_file_names.insert (to);
5299 filemap[from] = make_new_audio_path (to, name, name);
5301 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5303 orig_origin[afs] = afs->origin ();
5304 afs->set_origin ("");
5307 filemap[from] = make_new_media_path (from, name, name);
5314 if (compress_audio != NO_ENCODE) {
5316 progress->set_progress (2); // set to "encoding"
5317 progress->set_progress (0);
5320 Glib::Threads::Mutex::Lock lm (source_lock);
5321 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5322 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5323 if (!afs || afs->readable_length () == 0) {
5327 if (only_used_sources) {
5331 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5336 orig_sources[afs] = afs->path();
5337 orig_gain[afs] = afs->gain();
5339 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5341 std::string channelsuffix = "";
5342 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5343 /* embedded external multi-channel files are converted to multiple-mono */
5344 channelsuffix = string_compose ("-c%1", afs->channel ());
5346 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5347 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5349 /* avoid name collisions of external files with same name */
5350 if (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5351 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + "-1.flac");
5353 while (Glib::file_test (new_path, Glib::FILE_TEST_EXISTS)) {
5354 new_path = bump_name_once (new_path, '-');
5358 progress->descend ((float)afs->readable_length () / total_size);
5362 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5363 afs->replace_file (new_path);
5364 afs->set_gain (ns->gain(), true);
5367 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5371 progress->ascend ();
5377 progress->set_progress (-1); // set to "archiving"
5378 progress->set_progress (0);
5381 /* index files relevant for this session */
5382 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5383 vector<string> files;
5385 size_t prefix_len = (*sd).path.size();
5386 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5390 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5392 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5393 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5394 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5396 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5397 std::string from = *i;
5400 string filename = Glib::path_get_basename (from);
5401 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5402 if (filename == ".DS_STORE") {
5407 if (from.find (audiofile_dir_string) != string::npos) {
5409 } else if (from.find (midifile_dir_string) != string::npos) {
5410 filemap[from] = make_new_media_path (from, name, name);
5411 } else if (from.find (videofile_dir_string) != string::npos) {
5412 filemap[from] = make_new_media_path (from, name, name);
5414 bool do_copy = true;
5415 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5416 if (from.find (*v) != string::npos) {
5421 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5422 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5429 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5435 /* write session file */
5437 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5439 save_state (name, false, false, false, true, only_used_sources);
5441 save_default_options ();
5443 size_t prefix_len = _path.size();
5444 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5448 /* collect session-state files */
5449 vector<string> files;
5450 do_not_copy_extensions.clear ();
5451 do_not_copy_extensions.push_back (history_suffix);
5453 blacklist_dirs.clear ();
5454 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5456 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5457 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5458 std::string from = *i;
5459 bool do_copy = true;
5460 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5461 if (from.find (*v) != string::npos) {
5466 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5467 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5473 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5477 /* restore original values */
5480 set_snapshot_name (old_snapshot);
5481 (*_session_dir) = old_sd;
5482 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5483 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5485 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_origin.begin (); i != orig_origin.end (); ++i) {
5486 i->first->set_origin (i->second);
5488 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5489 i->first->replace_file (i->second);
5491 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5492 i->first->set_gain (i->second, true);
5495 int rv = ar.create (filemap, compression_level);
5496 remove_directory (to_dir);
5502 Session::undo (uint32_t n)
5504 if (actively_recording()) {
5512 Session::redo (uint32_t n)
5514 if (actively_recording()) {