2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
53 #include "pbd/locale_guard.h"
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/basename.h"
67 #include "pbd/debug.h"
68 #include "pbd/enumwriter.h"
69 #include "pbd/error.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/types_convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/audioregion.h"
84 #include "ardour/auditioner.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/boost_debug.h"
87 #include "ardour/butler.h"
88 #include "ardour/controllable_descriptor.h"
89 #include "ardour/control_protocol_manager.h"
90 #include "ardour/directory_names.h"
91 #include "ardour/disk_reader.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/selection.h"
118 #include "ardour/session.h"
119 #include "ardour/session_directory.h"
120 #include "ardour/session_metadata.h"
121 #include "ardour/session_playlists.h"
122 #include "ardour/session_state_utils.h"
123 #include "ardour/silentfilesource.h"
124 #include "ardour/smf_source.h"
125 #include "ardour/sndfilesource.h"
126 #include "ardour/source_factory.h"
127 #include "ardour/speakers.h"
128 #include "ardour/template_utils.h"
129 #include "ardour/tempo.h"
130 #include "ardour/ticker.h"
131 #include "ardour/types_convert.h"
132 #include "ardour/user_bundle.h"
133 #include "ardour/vca.h"
134 #include "ardour/vca_manager.h"
136 #include "control_protocol/control_protocol.h"
138 #include "LuaBridge/LuaBridge.h"
140 #include "pbd/i18n.h"
144 using namespace ARDOUR;
147 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
150 Session::pre_engine_init (string fullpath)
152 if (fullpath.empty()) {
154 throw failed_constructor();
157 /* discover canonical fullpath */
159 _path = canonical_path(fullpath);
162 if (Profile->get_trx() ) {
163 // Waves TracksLive has a usecase of session replacement with a new one.
164 // We should check session state file (<session_name>.ardour) existance
165 // to determine if the session is new or not
167 string full_session_name = Glib::build_filename( fullpath, _name );
168 full_session_name += statefile_suffix;
170 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
172 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
175 /* finish initialization that can't be done in a normal C++ constructor
179 timerclear (&last_mmc_step);
180 g_atomic_int_set (&processing_prohibited, 0);
181 g_atomic_int_set (&_record_status, Disabled);
182 g_atomic_int_set (&_playback_load, 100);
183 g_atomic_int_set (&_capture_load, 100);
185 _all_route_group->set_active (true, this);
186 interpolation.add_channel ();
188 if (config.get_use_video_sync()) {
189 waiting_for_sync_offset = true;
191 waiting_for_sync_offset = false;
194 last_rr_session_dir = session_dirs.begin();
196 set_history_depth (Config->get_history_depth());
198 /* default: assume simple stereo speaker configuration */
200 _speakers->setup_default_speakers (2);
202 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
203 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
204 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
205 add_controllable (_solo_cut_control);
207 /* These are all static "per-class" signals */
209 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
210 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
211 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
212 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
213 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
215 /* stop IO objects from doing stuff until we're ready for them */
217 Delivery::disable_panners ();
218 IO::disable_connecting ();
222 Session::post_engine_init ()
224 BootMessage (_("Set block size and sample rate"));
226 set_block_size (_engine.samples_per_cycle());
227 set_sample_rate (_engine.sample_rate());
229 BootMessage (_("Using configuration"));
231 _midi_ports = new MidiPortManager;
233 MIDISceneChanger* msc;
235 _scene_changer = msc = new MIDISceneChanger (*this);
236 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
237 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
239 boost::function<samplecnt_t(void)> timer_func (boost::bind (&Session::audible_sample, this, (bool*)(0)));
240 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
242 setup_midi_machine_control ();
244 if (_butler->start_thread()) {
245 error << _("Butler did not start") << endmsg;
249 if (start_midi_thread ()) {
250 error << _("MIDI I/O thread did not start") << endmsg;
254 setup_click_sounds (0);
255 setup_midi_control ();
257 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
258 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
261 /* tempo map requires sample rate knowledge */
264 _tempo_map = new TempoMap (_current_sample_rate);
265 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
266 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
267 } catch (std::exception const & e) {
268 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
271 error << _("Unknown exception during session setup") << endmsg;
276 /* MidiClock requires a tempo map */
279 midi_clock = new MidiClockTicker ();
280 midi_clock->set_session (this);
282 /* crossfades require sample rate knowledge */
284 SndFileSource::setup_standard_crossfades (*this, sample_rate());
285 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
286 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
288 DiskReader::allocate_working_buffers();
289 refresh_disk_space ();
291 /* we're finally ready to call set_state() ... all objects have
292 * been created, the engine is running.
297 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
298 error << _("Could not set session state from XML") << endmsg;
301 } catch (PBD::unknown_enumeration& e) {
302 error << _("Session state: ") << e.what() << endmsg;
306 // set_state() will call setup_raid_path(), but if it's a new session we need
307 // to call setup_raid_path() here.
308 setup_raid_path (_path);
313 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
314 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
316 Config->map_parameters (ff);
317 config.map_parameters (ft);
318 _butler->map_parameters ();
320 /* Reset all panners */
322 Delivery::reset_panners ();
324 /* this will cause the CPM to instantiate any protocols that are in use
325 * (or mandatory), which will pass it this Session, and then call
326 * set_state() on each instantiated protocol to match stored state.
329 ControlProtocolManager::instance().set_session (this);
331 /* This must be done after the ControlProtocolManager set_session above,
332 as it will set states for ports which the ControlProtocolManager creates.
335 // XXX set state of MIDI::Port's
336 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
338 /* And this must be done after the MIDI::Manager::set_port_states as
339 * it will try to make connections whose details are loaded by set_port_states.
344 /* Let control protocols know that we are now all connected, so they
345 * could start talking to surfaces if they want to.
348 ControlProtocolManager::instance().midi_connectivity_established ();
350 if (_is_new && !no_auto_connect()) {
351 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
352 auto_connect_master_bus ();
355 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
357 /* update latencies */
359 initialize_latencies ();
361 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
362 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
363 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
365 } catch (AudioEngine::PortRegistrationFailure& err) {
366 error << err.what() << endmsg;
368 } catch (std::exception const & e) {
369 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
372 error << _("Unknown exception during session setup") << endmsg;
376 BootMessage (_("Reset Remote Controls"));
378 // send_full_time_code (0);
379 _engine.transport_locate (0);
381 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
382 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
384 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
387 /* initial program change will be delivered later; see ::config_changed() */
389 _state_of_the_state = Clean;
391 Port::set_connecting_blocked (false);
393 DirtyChanged (); /* EMIT SIGNAL */
397 } else if (state_was_pending) {
399 remove_pending_capture_state ();
400 state_was_pending = false;
403 /* Now, finally, we can fill the playback buffers */
405 BootMessage (_("Filling playback buffers"));
407 boost::shared_ptr<RouteList> rl = routes.reader();
408 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
409 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
410 if (trk && !trk->is_private_route()) {
411 trk->seek (_transport_sample, true);
419 Session::session_loaded ()
423 _state_of_the_state = Clean;
425 DirtyChanged (); /* EMIT SIGNAL */
429 } else if (state_was_pending) {
431 remove_pending_capture_state ();
432 state_was_pending = false;
435 /* Now, finally, we can fill the playback buffers */
437 BootMessage (_("Filling playback buffers"));
438 force_locate (_transport_sample, false);
442 Session::raid_path () const
444 Searchpath raid_search_path;
446 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
447 raid_search_path += (*i).path;
450 return raid_search_path.to_string ();
454 Session::setup_raid_path (string path)
463 session_dirs.clear ();
465 Searchpath search_path(path);
466 Searchpath sound_search_path;
467 Searchpath midi_search_path;
469 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
471 sp.blocks = 0; // not needed
472 session_dirs.push_back (sp);
474 SessionDirectory sdir(sp.path);
476 sound_search_path += sdir.sound_path ();
477 midi_search_path += sdir.midi_path ();
480 // reset the round-robin soundfile path thingie
481 last_rr_session_dir = session_dirs.begin();
485 Session::path_is_within_session (const std::string& path)
487 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
488 if (PBD::path_is_within (i->path, path)) {
496 Session::ensure_subdirs ()
500 dir = session_directory().peak_path();
502 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
503 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
507 dir = session_directory().sound_path();
509 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
510 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
514 dir = session_directory().midi_path();
516 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
517 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
521 dir = session_directory().dead_path();
523 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
524 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
528 dir = session_directory().export_path();
530 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
531 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
535 dir = analysis_dir ();
537 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
538 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
542 dir = plugins_dir ();
544 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
545 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
549 dir = externals_dir ();
551 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
552 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
559 /** @param session_template directory containing session template, or empty.
560 * Caller must not hold process lock.
563 Session::create (const string& session_template, BusProfile* bus_profile)
565 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
566 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
570 if (ensure_subdirs ()) {
574 _writable = exists_and_writable (_path);
576 if (!session_template.empty()) {
577 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
579 FILE* in = g_fopen (in_path.c_str(), "rb");
582 /* no need to call legalize_for_path() since the string
583 * in session_template is already a legal path name
585 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
587 FILE* out = g_fopen (out_path.c_str(), "wb");
591 stringstream new_session;
594 size_t charsRead = fread (buf, sizeof(char), 1024, in);
597 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
602 if (charsRead == 0) {
605 new_session.write (buf, charsRead);
609 string file_contents = new_session.str();
610 size_t writeSize = file_contents.length();
611 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
612 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
620 if (!ARDOUR::Profile->get_trx()) {
621 /* Copy plugin state files from template to new session */
622 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
623 copy_recurse (template_plugins, plugins_dir ());
629 error << string_compose (_("Could not open %1 for writing session template"), out_path)
636 error << string_compose (_("Could not open session template %1 for reading"), in_path)
643 if (Profile->get_trx()) {
645 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
646 * Remember that this is a brand new session. Sessions
647 * loaded from saved state will get this range from the saved state.
650 set_session_range_location (0, 0);
652 /* Initial loop location, from absolute zero, length 10 seconds */
654 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
655 _locations->add (loc, true);
656 set_auto_loop_location (loc);
659 _state_of_the_state = Clean;
661 /* set up Master Out and Monitor Out if necessary */
665 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
666 if (bus_profile->master_out_channels) {
667 int rv = add_master_bus (count);
673 if (Config->get_use_monitor_bus())
674 add_monitor_section ();
682 Session::maybe_write_autosave()
684 if (dirty() && record_status() != Recording) {
685 save_state("", true);
690 Session::remove_pending_capture_state ()
692 std::string pending_state_file_path(_session_dir->root_path());
694 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
696 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
698 if (g_remove (pending_state_file_path.c_str()) != 0) {
699 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
700 pending_state_file_path, g_strerror (errno)) << endmsg;
704 /** Rename a state file.
705 * @param old_name Old snapshot name.
706 * @param new_name New snapshot name.
709 Session::rename_state (string old_name, string new_name)
711 if (old_name == _current_snapshot_name || old_name == _name) {
712 /* refuse to rename the current snapshot or the "main" one */
716 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
717 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
719 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
720 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
722 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
723 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
724 old_name, new_name, g_strerror(errno)) << endmsg;
728 /** Remove a state file.
729 * @param snapshot_name Snapshot name.
732 Session::remove_state (string snapshot_name)
734 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
735 // refuse to remove the current snapshot or the "main" one
739 std::string xml_path(_session_dir->root_path());
741 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
743 if (!create_backup_file (xml_path)) {
744 // don't remove it if a backup can't be made
745 // create_backup_file will log the error.
750 if (g_remove (xml_path.c_str()) != 0) {
751 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
752 xml_path, g_strerror (errno)) << endmsg;
756 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
758 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
760 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
763 std::string xml_path(_session_dir->root_path());
765 /* prevent concurrent saves from different threads */
767 Glib::Threads::Mutex::Lock lm (save_state_lock);
769 if (!_writable || (_state_of_the_state & CannotSave)) {
773 if (g_atomic_int_get(&_suspend_save)) {
777 _save_queued = false;
779 snapshot_t fork_state = NormalSave;
780 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) {
781 /* snapshot, close midi */
782 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
786 const int64_t save_start_time = g_get_monotonic_time();
789 /* tell sources we're saving first, in case they write out to a new file
790 * which should be saved with the state rather than the old one */
791 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
793 i->second->session_saved();
794 } catch (Evoral::SMF::FileError& e) {
795 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
799 SessionSaveUnderway (); /* EMIT SIGNAL */
801 bool mark_as_clean = true;
803 if (!snapshot_name.empty() && !switch_to_snapshot) {
804 mark_as_clean = false;
808 mark_as_clean = false;
809 tree.set_root (&get_template());
811 tree.set_root (&state (false, fork_state));
814 if (snapshot_name.empty()) {
815 snapshot_name = _current_snapshot_name;
816 } else if (switch_to_snapshot) {
817 set_snapshot_name (snapshot_name);
820 assert (!snapshot_name.empty());
824 /* proper save: use statefile_suffix (.ardour in English) */
826 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
828 /* make a backup copy of the old file */
830 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
831 // create_backup_file will log the error
837 /* pending save: use pending_suffix (.pending in English) */
838 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
841 std::string tmp_path(_session_dir->root_path());
842 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
845 cerr << "actually writing state to " << tmp_path << endl;
848 if (!tree.write (tmp_path)) {
849 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
850 if (g_remove (tmp_path.c_str()) != 0) {
851 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
852 tmp_path, g_strerror (errno)) << endmsg;
859 cerr << "renaming state to " << xml_path << endl;
862 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
863 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
864 tmp_path, xml_path, g_strerror(errno)) << endmsg;
865 if (g_remove (tmp_path.c_str()) != 0) {
866 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
867 tmp_path, g_strerror (errno)) << endmsg;
875 save_history (snapshot_name);
878 bool was_dirty = dirty();
880 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
883 DirtyChanged (); /* EMIT SIGNAL */
887 StateSaved (snapshot_name); /* EMIT SIGNAL */
891 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
892 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
898 Session::restore_state (string snapshot_name)
901 if (load_state (snapshot_name) == 0) {
902 set_state (*state_tree->root(), Stateful::loading_state_version);
906 // unknown_enumeration
914 Session::load_state (string snapshot_name)
919 state_was_pending = false;
921 /* check for leftover pending state from a crashed capture attempt */
923 std::string xmlpath(_session_dir->root_path());
924 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
926 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
928 /* there is pending state from a crashed capture attempt */
930 boost::optional<int> r = AskAboutPendingState();
931 if (r.get_value_or (1)) {
932 state_was_pending = true;
936 if (!state_was_pending) {
937 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
940 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
941 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
942 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
943 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
948 state_tree = new XMLTree;
952 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
954 if (!state_tree->read (xmlpath)) {
955 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
961 XMLNode const & root (*state_tree->root());
963 if (root.name() != X_("Session")) {
964 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
971 root.get_property ("version", version);
972 Stateful::loading_state_version = parse_stateful_loading_version (version);
974 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
975 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
976 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
979 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
981 std::string backup_path(_session_dir->root_path());
982 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
983 backup_path = Glib::build_filename (backup_path, backup_filename);
985 // only create a backup for a given statefile version once
987 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
989 VersionMismatch (xmlpath, backup_path);
991 if (!copy_file (xmlpath, backup_path)) {;
997 save_snapshot_name (snapshot_name);
1003 Session::load_options (const XMLNode& node)
1005 config.set_variables (node);
1010 Session::save_default_options ()
1012 return config.save_state();
1016 Session::get_state ()
1018 /* this is not directly called, but required by PBD::Stateful */
1020 return state (false, NormalSave);
1024 Session::get_template ()
1026 /* if we don't disable rec-enable, diskstreams
1027 will believe they need to store their capture
1028 sources in their state node.
1031 disable_record (false);
1033 return state (true, NormalSave);
1036 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1037 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1040 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1042 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1045 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1049 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1052 XMLNode* node = new XMLNode("TrackState"); // XXX
1055 PlaylistSet playlists; // SessionPlaylists
1058 // these will work with new_route_from_template()
1059 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1060 child = node->add_child ("Routes");
1061 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1062 if ((*i)->is_auditioner()) {
1065 if ((*i)->is_master() || (*i)->is_monitor()) {
1068 child->add_child_nocopy ((*i)->get_state());
1069 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1071 playlists.insert (track->playlist ());
1075 // on load, Regions in the playlists need to resolve and map Source-IDs
1076 // also playlist needs to be merged or created with new-name..
1077 // ... and Diskstream in tracks adjusted to use the correct playlist
1078 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1079 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1080 child->add_child_nocopy ((*i)->get_state ());
1081 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1082 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1083 const Region::SourceList& sl = (*s)->sources ();
1084 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1085 sources.insert (*sli);
1090 child = node->add_child ("Sources");
1091 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1092 child->add_child_nocopy ((*i)->get_state ());
1093 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1095 #ifdef PLATFORM_WINDOWS
1098 string p = fs->path ();
1099 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1103 std::string sn = Glib::build_filename (path, "share.axml");
1106 tree.set_root (node);
1107 return tree.write (sn.c_str());
1112 struct route_id_compare {
1114 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1116 return r1->id () < r2->id ();
1122 Session::state (bool save_template, snapshot_t snapshot_type)
1125 XMLNode* node = new XMLNode("Session");
1128 PBD::Unwinder<bool> uw (Automatable::skip_saving_automation, save_template);
1130 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1132 child = node->add_child ("ProgramVersion");
1133 child->set_property("created-with", created_with);
1135 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1136 child->set_property("modified-with", modified_with);
1138 /* store configuration settings */
1140 if (!save_template) {
1142 node->set_property ("name", _name);
1143 node->set_property ("sample-rate", _base_sample_rate);
1145 if (session_dirs.size() > 1) {
1149 vector<space_and_path>::iterator i = session_dirs.begin();
1150 vector<space_and_path>::iterator next;
1152 ++i; /* skip the first one */
1156 while (i != session_dirs.end()) {
1160 if (next != session_dirs.end()) {
1161 p += G_SEARCHPATH_SEPARATOR;
1170 child = node->add_child ("Path");
1171 child->add_content (p);
1173 node->set_property ("end-is-free", _session_range_end_is_free);
1176 /* save the ID counter */
1178 node->set_property ("id-counter", ID::counter());
1180 node->set_property ("name-counter", name_id_counter ());
1182 /* save the event ID counter */
1184 node->set_property ("event-counter", Evoral::event_id_counter());
1186 /* save the VCA counter */
1188 node->set_property ("vca-counter", VCA::get_next_vca_number());
1190 /* various options */
1192 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1193 if (!midi_port_nodes.empty()) {
1194 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1195 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1196 midi_port_stuff->add_child_nocopy (**n);
1198 node->add_child_nocopy (*midi_port_stuff);
1201 XMLNode& cfgxml (config.get_variables ());
1202 if (save_template) {
1203 /* exclude search-paths from template */
1204 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1205 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1206 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1208 node->add_child_nocopy (cfgxml);
1210 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1212 child = node->add_child ("Sources");
1214 if (!save_template) {
1215 Glib::Threads::Mutex::Lock sl (source_lock);
1217 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1219 /* Don't save information about non-file Sources, or
1220 * about non-destructive file sources that are empty
1221 * and unused by any regions.
1223 boost::shared_ptr<FileSource> fs;
1225 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1229 if (!fs->destructive()) {
1230 if (fs->empty() && !fs->used()) {
1235 if (snapshot_type != NormalSave && fs->within_session ()) {
1236 /* copy MIDI sources to new file
1238 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1239 * because the GUI (midi_region) has a direct pointer to the midi-model
1240 * of the source, as does UndoTransaction.
1242 * On the upside, .mid files are not kept open. The file is only open
1243 * when reading the model initially and when flushing the model to disk:
1244 * source->session_saved () or export.
1246 * We can change the _path of the existing source under the hood, keeping
1247 * all IDs, references and pointers intact.
1249 boost::shared_ptr<SMFSource> ms;
1250 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1251 const std::string ancestor_name = ms->ancestor_name();
1252 const std::string base = PBD::basename_nosuffix(ancestor_name);
1253 const string path = new_midi_source_path (base, false);
1255 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1256 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1257 Source::Lock lm (ms->mutex());
1259 // TODO special-case empty, removable() files: just create a new removable.
1260 // (load + write flushes the model and creates the file)
1262 ms->load_model (lm);
1264 if (ms->write_to (lm, newsrc, Temporal::Beats(), std::numeric_limits<Temporal::Beats>::max())) {
1265 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1267 if (snapshot_type == SnapshotKeep) {
1268 /* keep working on current session.
1270 * Save snapshot-state with the original filename.
1271 * Switch to use new path for future saves of the main session.
1273 child->add_child_nocopy (ms->get_state());
1277 * ~SMFSource unlinks removable() files.
1279 std::string npath (ms->path ());
1280 ms->replace_file (newsrc->path ());
1281 newsrc->replace_file (npath);
1283 if (snapshot_type == SwitchToSnapshot) {
1284 /* save and switch to snapshot.
1286 * Leave the old file in place (as is).
1287 * Snapshot uses new source directly
1289 child->add_child_nocopy (ms->get_state());
1296 child->add_child_nocopy (siter->second->get_state());
1300 child = node->add_child ("Regions");
1302 if (!save_template) {
1303 Glib::Threads::Mutex::Lock rl (region_lock);
1304 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1305 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1306 boost::shared_ptr<Region> r = i->second;
1307 /* only store regions not attached to playlists */
1308 if (r->playlist() == 0) {
1309 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1310 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1312 child->add_child_nocopy (r->get_state ());
1317 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1319 if (!cassocs.empty()) {
1320 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1322 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1323 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1324 can->set_property (X_("copy"), i->first->id());
1325 can->set_property (X_("original"), i->second->id());
1326 ca->add_child_nocopy (*can);
1331 if (!save_template) {
1333 node->add_child_nocopy (_selection->get_state());
1336 node->add_child_nocopy (_locations->get_state());
1339 Locations loc (*this);
1340 const bool was_dirty = dirty();
1341 // for a template, just create a new Locations, populate it
1342 // with the default start and end, and get the state for that.
1343 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1344 range->set (max_samplepos, 0);
1346 XMLNode& locations_state = loc.get_state();
1348 if (ARDOUR::Profile->get_trx() && _locations) {
1349 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1350 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1351 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1352 locations_state.add_child_nocopy ((*i)->get_state ());
1356 node->add_child_nocopy (locations_state);
1358 /* adding a location above will have marked the session
1359 * dirty. This is an artifact, so fix it if the session wasn't
1364 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1368 child = node->add_child ("Bundles");
1370 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1371 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1372 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1374 child->add_child_nocopy (b->get_state());
1379 node->add_child_nocopy (_vca_manager->get_state());
1381 child = node->add_child ("Routes");
1383 boost::shared_ptr<RouteList> r = routes.reader ();
1385 route_id_compare cmp;
1386 RouteList xml_node_order (*r);
1387 xml_node_order.sort (cmp);
1389 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1390 if (!(*i)->is_auditioner()) {
1391 if (save_template) {
1392 child->add_child_nocopy ((*i)->get_template());
1394 child->add_child_nocopy ((*i)->get_state());
1400 playlists->add_state (node, save_template, /* include unused*/ true);
1402 child = node->add_child ("RouteGroups");
1403 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1404 child->add_child_nocopy ((*i)->get_state());
1408 XMLNode* gain_child = node->add_child ("Click");
1409 gain_child->add_child_nocopy (_click_io->get_state ());
1410 gain_child->add_child_nocopy (_click_gain->get_state ());
1414 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1415 ltc_input_child->add_child_nocopy (_ltc_input->get_state ());
1419 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1420 ltc_output_child->add_child_nocopy (_ltc_output->get_state ());
1423 node->add_child_nocopy (_speakers->get_state());
1424 node->add_child_nocopy (_tempo_map->get_state());
1425 node->add_child_nocopy (get_control_protocol_state());
1428 node->add_child_copy (*_extra_xml);
1432 Glib::Threads::Mutex::Lock lm (lua_lock);
1435 luabridge::LuaRef savedstate ((*_lua_save)());
1436 saved = savedstate.cast<std::string>();
1438 lua.collect_garbage ();
1441 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1442 std::string b64s (b64);
1445 XMLNode* script_node = new XMLNode (X_("Script"));
1446 script_node->set_property (X_("lua"), LUA_VERSION);
1447 script_node->add_content (b64s);
1448 node->add_child_nocopy (*script_node);
1455 Session::get_control_protocol_state ()
1457 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1458 return cpm.get_state();
1462 Session::set_state (const XMLNode& node, int version)
1469 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1471 if (node.name() != X_("Session")) {
1472 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1476 node.get_property ("name", _name);
1478 if (node.get_property (X_("sample-rate"), _base_sample_rate)) {
1480 _nominal_sample_rate = _base_sample_rate;
1482 assert (AudioEngine::instance()->running ());
1483 if (_base_sample_rate != AudioEngine::instance()->sample_rate ()) {
1484 boost::optional<int> r = AskAboutSampleRateMismatch (_base_sample_rate, _current_sample_rate);
1485 if (r.get_value_or (0)) {
1491 created_with = "unknown";
1492 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1493 child->get_property (X_("created-with"), created_with);
1496 setup_raid_path(_session_dir->root_path());
1498 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1501 if (node.get_property (X_("id-counter"), counter)) {
1502 ID::init_counter (counter);
1504 /* old sessions used a timebased counter, so fake
1505 * the startup ID counter based on a standard
1510 ID::init_counter (now);
1513 if (node.get_property (X_("name-counter"), counter)) {
1514 init_name_id_counter (counter);
1517 if (node.get_property (X_("event-counter"), counter)) {
1518 Evoral::init_event_id_counter (counter);
1521 if (node.get_property (X_("vca-counter"), counter)) {
1522 VCA::set_next_vca_number (counter);
1524 VCA::set_next_vca_number (1);
1527 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1528 _midi_ports->set_midi_port_states (child->children());
1531 IO::disable_connecting ();
1533 Stateful::save_extra_xml (node);
1535 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1536 load_options (*child);
1537 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1538 load_options (*child);
1540 error << _("Session: XML state has no options section") << endmsg;
1543 if (version >= 3000) {
1544 if ((child = find_named_node (node, "Metadata")) == 0) {
1545 warning << _("Session: XML state has no metadata section") << endmsg;
1546 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1551 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1552 _speakers->set_state (*child, version);
1555 if ((child = find_named_node (node, "Sources")) == 0) {
1556 error << _("Session: XML state has no sources section") << endmsg;
1558 } else if (load_sources (*child)) {
1562 if ((child = find_named_node (node, "TempoMap")) == 0) {
1563 error << _("Session: XML state has no Tempo Map section") << endmsg;
1565 } else if (_tempo_map->set_state (*child, version)) {
1569 if ((child = find_named_node (node, "Locations")) == 0) {
1570 error << _("Session: XML state has no locations section") << endmsg;
1572 } else if (_locations->set_state (*child, version)) {
1576 locations_changed ();
1578 if (_session_range_location) {
1579 AudioFileSource::set_header_position_offset (_session_range_location->start());
1582 if ((child = find_named_node (node, "Regions")) == 0) {
1583 error << _("Session: XML state has no Regions section") << endmsg;
1585 } else if (load_regions (*child)) {
1589 if ((child = find_named_node (node, "Playlists")) == 0) {
1590 error << _("Session: XML state has no playlists section") << endmsg;
1592 } else if (playlists->load (*this, *child)) {
1596 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1598 } else if (playlists->load_unused (*this, *child)) {
1602 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1603 if (load_compounds (*child)) {
1608 if (version >= 3000) {
1609 if ((child = find_named_node (node, "Bundles")) == 0) {
1610 warning << _("Session: XML state has no bundles section") << endmsg;
1613 /* We can't load Bundles yet as they need to be able
1614 * to convert from port names to Port objects, which can't happen until
1616 _bundle_xml_node = new XMLNode (*child);
1620 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1621 _vca_manager->set_state (*child, version);
1624 if ((child = find_named_node (node, "Routes")) == 0) {
1625 error << _("Session: XML state has no routes section") << endmsg;
1627 } else if (load_routes (*child, version)) {
1631 /* Now that we have Routes and masters loaded, connect them if appropriate */
1633 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1635 if (version >= 3000) {
1637 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1638 error << _("Session: XML state has no route groups section") << endmsg;
1640 } else if (load_route_groups (*child, version)) {
1644 } else if (version < 3000) {
1646 if ((child = find_named_node (node, "EditGroups")) == 0) {
1647 error << _("Session: XML state has no edit groups section") << endmsg;
1649 } else if (load_route_groups (*child, version)) {
1653 if ((child = find_named_node (node, "MixGroups")) == 0) {
1654 error << _("Session: XML state has no mix groups section") << endmsg;
1656 } else if (load_route_groups (*child, version)) {
1661 if ((child = find_named_node (node, "Click")) == 0) {
1662 warning << _("Session: XML state has no click section") << endmsg;
1663 } else if (_click_io) {
1664 setup_click_state (&node);
1667 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1668 ControlProtocolManager::instance().set_state (*child, version);
1671 if ((child = find_named_node (node, "Script"))) {
1672 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1673 if (!(*n)->is_content ()) { continue; }
1675 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1677 Glib::Threads::Mutex::Lock lm (lua_lock);
1678 (*_lua_load)(std::string ((const char*)buf, size));
1679 } catch (luabridge::LuaException const& e) {
1680 cerr << "LuaException:" << e.what () << endl;
1686 if ((child = find_named_node (node, X_("Selection")))) {
1687 _selection->set_state (*child, version);
1690 update_route_record_state ();
1692 /* here beginneth the second phase ... */
1693 set_snapshot_name (_current_snapshot_name);
1695 StateReady (); /* EMIT SIGNAL */
1708 Session::load_routes (const XMLNode& node, int version)
1711 XMLNodeConstIterator niter;
1712 RouteList new_routes;
1714 nlist = node.children();
1718 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1720 boost::shared_ptr<Route> route;
1722 if (version < 3000) {
1723 route = XMLRouteFactory_2X (**niter, version);
1724 } else if (version < 5000) {
1725 route = XMLRouteFactory_3X (**niter, version);
1727 route = XMLRouteFactory (**niter, version);
1731 error << _("Session: cannot create Route from XML description.") << endmsg;
1735 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1737 new_routes.push_back (route);
1740 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1742 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1744 BootMessage (_("Finished adding tracks/busses"));
1749 boost::shared_ptr<Route>
1750 Session::XMLRouteFactory (const XMLNode& node, int version)
1752 boost::shared_ptr<Route> ret;
1754 if (node.name() != "Route") {
1758 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1761 pl_prop = node.property (X_("midi-playlist"));
1764 DataType type = DataType::AUDIO;
1765 node.get_property("default-type", type);
1767 assert (type != DataType::NIL);
1771 /* has at least 1 playlist, therefore a track ... */
1773 boost::shared_ptr<Track> track;
1775 if (type == DataType::AUDIO) {
1776 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1778 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1781 if (track->init()) {
1785 if (track->set_state (node, version)) {
1789 BOOST_MARK_TRACK (track);
1793 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1794 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1797 if (r->init () == 0 && r->set_state (node, version) == 0) {
1798 BOOST_MARK_ROUTE (r);
1806 boost::shared_ptr<Route>
1807 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1809 boost::shared_ptr<Route> ret;
1811 if (node.name() != "Route") {
1815 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1817 DataType type = DataType::AUDIO;
1818 node.get_property("default-type", type);
1820 assert (type != DataType::NIL);
1824 boost::shared_ptr<Track> track;
1826 if (type == DataType::AUDIO) {
1827 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1829 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1832 if (track->init()) {
1836 if (track->set_state (node, version)) {
1840 BOOST_MARK_TRACK (track);
1844 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1845 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1847 if (r->init () == 0 && r->set_state (node, version) == 0) {
1848 BOOST_MARK_ROUTE (r);
1856 boost::shared_ptr<Route>
1857 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1859 boost::shared_ptr<Route> ret;
1861 if (node.name() != "Route") {
1865 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1867 ds_prop = node.property (X_("diskstream"));
1870 DataType type = DataType::AUDIO;
1871 node.get_property("default-type", type);
1873 assert (type != DataType::NIL);
1877 /* see comment in current ::set_state() regarding diskstream
1878 * state and DiskReader/DiskWRiter.
1881 error << _("Could not find diskstream for route") << endmsg;
1882 return boost::shared_ptr<Route> ();
1884 boost::shared_ptr<Track> track;
1886 if (type == DataType::AUDIO) {
1887 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1889 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1892 if (track->init()) {
1896 if (track->set_state (node, version)) {
1900 BOOST_MARK_TRACK (track);
1904 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1905 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1907 if (r->init () == 0 && r->set_state (node, version) == 0) {
1908 BOOST_MARK_ROUTE (r);
1917 Session::load_regions (const XMLNode& node)
1920 XMLNodeConstIterator niter;
1921 boost::shared_ptr<Region> region;
1923 nlist = node.children();
1927 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1928 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1929 error << _("Session: cannot create Region from XML description.");
1930 XMLProperty const * name = (**niter).property("name");
1933 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1944 Session::load_compounds (const XMLNode& node)
1946 XMLNodeList calist = node.children();
1947 XMLNodeConstIterator caiter;
1948 XMLProperty const * caprop;
1950 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1951 XMLNode* ca = *caiter;
1955 if ((caprop = ca->property (X_("original"))) == 0) {
1958 orig_id = caprop->value();
1960 if ((caprop = ca->property (X_("copy"))) == 0) {
1963 copy_id = caprop->value();
1965 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1966 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1968 if (!orig || !copy) {
1969 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1975 RegionFactory::add_compound_association (orig, copy);
1982 Session::load_nested_sources (const XMLNode& node)
1985 XMLNodeConstIterator niter;
1987 nlist = node.children();
1989 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1990 if ((*niter)->name() == "Source") {
1992 /* it may already exist, so don't recreate it unnecessarily
1995 XMLProperty const * prop = (*niter)->property (X_("id"));
1997 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
2001 ID source_id (prop->value());
2003 if (!source_by_id (source_id)) {
2006 SourceFactory::create (*this, **niter, true);
2008 catch (failed_constructor& err) {
2009 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2016 boost::shared_ptr<Region>
2017 Session::XMLRegionFactory (const XMLNode& node, bool full)
2019 XMLProperty const * type = node.property("type");
2023 const XMLNodeList& nlist = node.children();
2025 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2026 XMLNode *child = (*niter);
2027 if (child->name() == "NestedSource") {
2028 load_nested_sources (*child);
2032 if (!type || type->value() == "audio") {
2033 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2034 } else if (type->value() == "midi") {
2035 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2038 } catch (failed_constructor& err) {
2039 return boost::shared_ptr<Region> ();
2042 return boost::shared_ptr<Region> ();
2045 boost::shared_ptr<AudioRegion>
2046 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2048 XMLProperty const * prop;
2049 boost::shared_ptr<Source> source;
2050 boost::shared_ptr<AudioSource> as;
2052 SourceList master_sources;
2053 uint32_t nchans = 1;
2056 if (node.name() != X_("Region")) {
2057 return boost::shared_ptr<AudioRegion>();
2060 node.get_property (X_("channels"), nchans);
2062 if ((prop = node.property ("name")) == 0) {
2063 cerr << "no name for this region\n";
2067 if ((prop = node.property (X_("source-0"))) == 0) {
2068 if ((prop = node.property ("source")) == 0) {
2069 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2070 return boost::shared_ptr<AudioRegion>();
2074 PBD::ID s_id (prop->value());
2076 if ((source = source_by_id (s_id)) == 0) {
2077 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2078 return boost::shared_ptr<AudioRegion>();
2081 as = boost::dynamic_pointer_cast<AudioSource>(source);
2083 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2084 return boost::shared_ptr<AudioRegion>();
2087 sources.push_back (as);
2089 /* pickup other channels */
2091 for (uint32_t n=1; n < nchans; ++n) {
2092 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2093 if ((prop = node.property (buf)) != 0) {
2095 PBD::ID id2 (prop->value());
2097 if ((source = source_by_id (id2)) == 0) {
2098 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2099 return boost::shared_ptr<AudioRegion>();
2102 as = boost::dynamic_pointer_cast<AudioSource>(source);
2104 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2105 return boost::shared_ptr<AudioRegion>();
2107 sources.push_back (as);
2111 for (uint32_t n = 0; n < nchans; ++n) {
2112 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2113 if ((prop = node.property (buf)) != 0) {
2115 PBD::ID id2 (prop->value());
2117 if ((source = source_by_id (id2)) == 0) {
2118 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << 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"), id2) << endmsg;
2125 return boost::shared_ptr<AudioRegion>();
2127 master_sources.push_back (as);
2132 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2134 /* a final detail: this is the one and only place that we know how long missing files are */
2136 if (region->whole_file()) {
2137 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2138 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2140 sfp->set_length (region->length());
2145 if (!master_sources.empty()) {
2146 if (master_sources.size() != nchans) {
2147 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2149 region->set_master_sources (master_sources);
2157 catch (failed_constructor& err) {
2158 return boost::shared_ptr<AudioRegion>();
2162 boost::shared_ptr<MidiRegion>
2163 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2165 XMLProperty const * prop;
2166 boost::shared_ptr<Source> source;
2167 boost::shared_ptr<MidiSource> ms;
2170 if (node.name() != X_("Region")) {
2171 return boost::shared_ptr<MidiRegion>();
2174 if ((prop = node.property ("name")) == 0) {
2175 cerr << "no name for this region\n";
2179 if ((prop = node.property (X_("source-0"))) == 0) {
2180 if ((prop = node.property ("source")) == 0) {
2181 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2182 return boost::shared_ptr<MidiRegion>();
2186 PBD::ID s_id (prop->value());
2188 if ((source = source_by_id (s_id)) == 0) {
2189 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2190 return boost::shared_ptr<MidiRegion>();
2193 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2195 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2196 return boost::shared_ptr<MidiRegion>();
2199 sources.push_back (ms);
2202 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2203 /* a final detail: this is the one and only place that we know how long missing files are */
2205 if (region->whole_file()) {
2206 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2207 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2209 sfp->set_length (region->length());
2217 catch (failed_constructor& err) {
2218 return boost::shared_ptr<MidiRegion>();
2223 Session::get_sources_as_xml ()
2226 XMLNode* node = new XMLNode (X_("Sources"));
2227 Glib::Threads::Mutex::Lock lm (source_lock);
2229 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2230 node->add_child_nocopy (i->second->get_state());
2237 Session::reset_write_sources (bool mark_write_complete, bool force)
2239 boost::shared_ptr<RouteList> rl = routes.reader();
2240 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2241 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2243 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2244 tr->reset_write_sources(mark_write_complete, force);
2245 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2251 Session::load_sources (const XMLNode& node)
2254 XMLNodeConstIterator niter;
2255 /* don't need this but it stops some
2256 * versions of gcc complaining about
2257 * discarded return values.
2259 boost::shared_ptr<Source> source;
2261 nlist = node.children();
2264 std::map<std::string, std::string> relocation;
2266 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2267 #ifdef PLATFORM_WINDOWS
2271 XMLNode srcnode (**niter);
2272 bool try_replace_abspath = true;
2276 #ifdef PLATFORM_WINDOWS
2277 // do not show "insert media" popups (files embedded from removable media).
2278 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2280 if ((source = XMLSourceFactory (srcnode)) == 0) {
2281 error << _("Session: cannot create Source from XML description.") << endmsg;
2283 #ifdef PLATFORM_WINDOWS
2284 SetErrorMode(old_mode);
2287 } catch (MissingSource& err) {
2288 #ifdef PLATFORM_WINDOWS
2289 SetErrorMode(old_mode);
2292 /* try previous abs path replacements first */
2293 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2294 std::string dir = Glib::path_get_dirname (err.path);
2295 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2296 if (rl != relocation.end ()) {
2297 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2298 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2299 srcnode.set_property ("origin", newpath);
2300 try_replace_abspath = false;
2307 _missing_file_replacement = "";
2309 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2310 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2311 PROGRAM_NAME) << endmsg;
2315 if (!no_questions_about_missing_files) {
2316 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2321 switch (user_choice) {
2323 /* user added a new search location
2324 * or selected a new absolute path,
2326 if (Glib::path_is_absolute (err.path)) {
2327 if (!_missing_file_replacement.empty ()) {
2328 /* replace origin, in XML */
2329 std::string newpath = Glib::build_filename (
2330 _missing_file_replacement, Glib::path_get_basename (err.path));
2331 srcnode.set_property ("origin", newpath);
2332 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2333 _missing_file_replacement = "";
2340 /* user asked to quit the entire session load */
2344 no_questions_about_missing_files = true;
2348 no_questions_about_missing_files = true;
2355 case DataType::AUDIO:
2356 source = SourceFactory::createSilent (*this, **niter, max_samplecnt, _current_sample_rate);
2359 case DataType::MIDI:
2360 /* The MIDI file is actually missing so
2361 * just create a new one in the same
2362 * location. Do not announce its
2366 if (!Glib::path_is_absolute (err.path)) {
2367 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2369 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2374 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2375 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_sample_rate, false, false);
2376 /* reset ID to match the missing one */
2377 source->set_id (**niter);
2378 /* Now we can announce it */
2379 SourceFactory::SourceCreated (source);
2390 boost::shared_ptr<Source>
2391 Session::XMLSourceFactory (const XMLNode& node)
2393 if (node.name() != "Source") {
2394 return boost::shared_ptr<Source>();
2398 /* note: do peak building in another thread when loading session state */
2399 return SourceFactory::create (*this, node, true);
2402 catch (failed_constructor& err) {
2403 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2404 return boost::shared_ptr<Source>();
2409 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2411 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2415 bool absolute_path = Glib::path_is_absolute (template_name);
2417 /* directory to put the template in */
2418 std::string template_dir_path;
2420 if (!absolute_path) {
2421 std::string user_template_dir(user_template_directory());
2423 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2424 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2425 user_template_dir, g_strerror (errno)) << endmsg;
2429 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2431 template_dir_path = template_name;
2434 if (!ARDOUR::Profile->get_trx()) {
2435 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2436 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2437 template_dir_path) << endmsg;
2441 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2442 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2443 template_dir_path, g_strerror (errno)) << endmsg;
2449 std::string template_file_path;
2451 if (ARDOUR::Profile->get_trx()) {
2452 template_file_path = template_name;
2454 if (absolute_path) {
2455 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2457 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2461 SessionSaveUnderway (); /* EMIT SIGNAL */
2466 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2467 root = &get_template ();
2470 root->remove_nodes_and_delete (X_("description"));
2472 if (!description.empty()) {
2473 XMLNode* desc = new XMLNode (X_("description"));
2474 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2475 desc->add_child_nocopy (*desc_cont);
2477 root->add_child_nocopy (*desc);
2480 tree.set_root (root);
2482 if (!tree.write (template_file_path)) {
2483 error << _("template not saved") << endmsg;
2487 store_recent_templates (template_file_path);
2493 Session::refresh_disk_space ()
2495 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2497 Glib::Threads::Mutex::Lock lm (space_lock);
2499 /* get freespace on every FS that is part of the session path */
2501 _total_free_4k_blocks = 0;
2502 _total_free_4k_blocks_uncertain = false;
2504 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2505 #if defined(__NetBSD__)
2506 struct statvfs statfsbuf;
2508 statvfs (i->path.c_str(), &statfsbuf);
2510 struct statfs statfsbuf;
2512 statfs (i->path.c_str(), &statfsbuf);
2514 double const scale = statfsbuf.f_bsize / 4096.0;
2516 /* See if this filesystem is read-only */
2517 struct statvfs statvfsbuf;
2518 statvfs (i->path.c_str(), &statvfsbuf);
2520 /* f_bavail can be 0 if it is undefined for whatever
2521 filesystem we are looking at; Samba shares mounted
2522 via GVFS are an example of this.
2524 if (statfsbuf.f_bavail == 0) {
2525 /* block count unknown */
2527 i->blocks_unknown = true;
2528 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2529 /* read-only filesystem */
2531 i->blocks_unknown = false;
2533 /* read/write filesystem with known space */
2534 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2535 i->blocks_unknown = false;
2538 _total_free_4k_blocks += i->blocks;
2539 if (i->blocks_unknown) {
2540 _total_free_4k_blocks_uncertain = true;
2543 #elif defined PLATFORM_WINDOWS
2544 vector<string> scanned_volumes;
2545 vector<string>::iterator j;
2546 vector<space_and_path>::iterator i;
2547 DWORD nSectorsPerCluster, nBytesPerSector,
2548 nFreeClusters, nTotalClusters;
2552 _total_free_4k_blocks = 0;
2554 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2555 strncpy (disk_drive, (*i).path.c_str(), 3);
2559 volume_found = false;
2560 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2562 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2563 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2564 i->blocks = (uint32_t)(nFreeBytes / 4096);
2566 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2567 if (0 == j->compare(disk_drive)) {
2568 volume_found = true;
2573 if (!volume_found) {
2574 scanned_volumes.push_back(disk_drive);
2575 _total_free_4k_blocks += i->blocks;
2580 if (0 == _total_free_4k_blocks) {
2581 strncpy (disk_drive, path().c_str(), 3);
2584 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2586 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2587 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2588 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2595 Session::get_best_session_directory_for_new_audio ()
2597 vector<space_and_path>::iterator i;
2598 string result = _session_dir->root_path();
2600 /* handle common case without system calls */
2602 if (session_dirs.size() == 1) {
2606 /* OK, here's the algorithm we're following here:
2608 We want to select which directory to use for
2609 the next file source to be created. Ideally,
2610 we'd like to use a round-robin process so as to
2611 get maximum performance benefits from splitting
2612 the files across multiple disks.
2614 However, in situations without much diskspace, an
2615 RR approach may end up filling up a filesystem
2616 with new files while others still have space.
2617 Its therefore important to pay some attention to
2618 the freespace in the filesystem holding each
2619 directory as well. However, if we did that by
2620 itself, we'd keep creating new files in the file
2621 system with the most space until it was as full
2622 as all others, thus negating any performance
2623 benefits of this RAID-1 like approach.
2625 So, we use a user-configurable space threshold. If
2626 there are at least 2 filesystems with more than this
2627 much space available, we use RR selection between them.
2628 If not, then we pick the filesystem with the most space.
2630 This gets a good balance between the two
2634 refresh_disk_space ();
2636 int free_enough = 0;
2638 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2639 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2644 if (free_enough >= 2) {
2645 /* use RR selection process, ensuring that the one
2649 i = last_rr_session_dir;
2652 if (++i == session_dirs.end()) {
2653 i = session_dirs.begin();
2656 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2657 SessionDirectory sdir(i->path);
2658 if (sdir.create ()) {
2660 last_rr_session_dir = i;
2665 } while (i != last_rr_session_dir);
2669 /* pick FS with the most freespace (and that
2670 seems to actually work ...)
2673 vector<space_and_path> sorted;
2674 space_and_path_ascending_cmp cmp;
2676 sorted = session_dirs;
2677 sort (sorted.begin(), sorted.end(), cmp);
2679 for (i = sorted.begin(); i != sorted.end(); ++i) {
2680 SessionDirectory sdir(i->path);
2681 if (sdir.create ()) {
2683 last_rr_session_dir = i;
2693 Session::automation_dir () const
2695 return Glib::build_filename (_path, automation_dir_name);
2699 Session::analysis_dir () const
2701 return Glib::build_filename (_path, analysis_dir_name);
2705 Session::plugins_dir () const
2707 return Glib::build_filename (_path, plugins_dir_name);
2711 Session::externals_dir () const
2713 return Glib::build_filename (_path, externals_dir_name);
2717 Session::load_bundles (XMLNode const & node)
2719 XMLNodeList nlist = node.children();
2720 XMLNodeConstIterator niter;
2724 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2725 if ((*niter)->name() == "InputBundle") {
2726 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2727 } else if ((*niter)->name() == "OutputBundle") {
2728 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2730 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2739 Session::load_route_groups (const XMLNode& node, int version)
2741 XMLNodeList nlist = node.children();
2742 XMLNodeConstIterator niter;
2746 if (version >= 3000) {
2748 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2749 if ((*niter)->name() == "RouteGroup") {
2750 RouteGroup* rg = new RouteGroup (*this, "");
2751 add_route_group (rg);
2752 rg->set_state (**niter, version);
2756 } else if (version < 3000) {
2758 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2759 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2760 RouteGroup* rg = new RouteGroup (*this, "");
2761 add_route_group (rg);
2762 rg->set_state (**niter, version);
2771 state_file_filter (const string &str, void* /*arg*/)
2773 return (str.length() > strlen(statefile_suffix) &&
2774 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2778 remove_end(string state)
2780 string statename(state);
2782 string::size_type start,end;
2783 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2784 statename = statename.substr (start+1);
2787 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2788 end = statename.length();
2791 return string(statename.substr (0, end));
2795 Session::possible_states (string path)
2797 vector<string> states;
2798 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2800 transform(states.begin(), states.end(), states.begin(), remove_end);
2802 sort (states.begin(), states.end());
2808 Session::possible_states () const
2810 return possible_states(_path);
2814 Session::new_route_group (const std::string& name)
2816 RouteGroup* rg = NULL;
2818 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2819 if ((*i)->name () == name) {
2826 rg = new RouteGroup (*this, name);
2827 add_route_group (rg);
2833 Session::add_route_group (RouteGroup* g)
2835 _route_groups.push_back (g);
2836 route_group_added (g); /* EMIT SIGNAL */
2838 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2839 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2840 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2846 Session::remove_route_group (RouteGroup& rg)
2848 list<RouteGroup*>::iterator i;
2850 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2851 _route_groups.erase (i);
2854 route_group_removed (); /* EMIT SIGNAL */
2858 /** Set a new order for our route groups, without adding or removing any.
2859 * @param groups Route group list in the new order.
2862 Session::reorder_route_groups (list<RouteGroup*> groups)
2864 _route_groups = groups;
2866 route_groups_reordered (); /* EMIT SIGNAL */
2872 Session::route_group_by_name (string name)
2874 list<RouteGroup *>::iterator i;
2876 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2877 if ((*i)->name() == name) {
2885 Session::all_route_group() const
2887 return *_all_route_group;
2891 Session::add_commands (vector<Command*> const & cmds)
2893 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2899 Session::add_command (Command* const cmd)
2901 assert (_current_trans);
2902 DEBUG_UNDO_HISTORY (
2903 string_compose ("Current Undo Transaction %1, adding command: %2",
2904 _current_trans->name (),
2906 _current_trans->add_command (cmd);
2909 PBD::StatefulDiffCommand*
2910 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2912 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2918 Session::begin_reversible_command (const string& name)
2920 begin_reversible_command (g_quark_from_string (name.c_str ()));
2923 /** Begin a reversible command using a GQuark to identify it.
2924 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2925 * but there must be as many begin...()s as there are commit...()s.
2928 Session::begin_reversible_command (GQuark q)
2930 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2931 to hold all the commands that are committed. This keeps the order of
2932 commands correct in the history.
2935 if (_current_trans == 0) {
2936 DEBUG_UNDO_HISTORY (string_compose (
2937 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2939 /* start a new transaction */
2940 assert (_current_trans_quarks.empty ());
2941 _current_trans = new UndoTransaction();
2942 _current_trans->set_name (g_quark_to_string (q));
2944 DEBUG_UNDO_HISTORY (
2945 string_compose ("Begin Reversible Command, current transaction: %1",
2946 _current_trans->name ()));
2949 _current_trans_quarks.push_front (q);
2953 Session::abort_reversible_command ()
2955 if (_current_trans != 0) {
2956 DEBUG_UNDO_HISTORY (
2957 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2958 _current_trans->clear();
2959 delete _current_trans;
2961 _current_trans_quarks.clear();
2966 Session::commit_reversible_command (Command *cmd)
2968 assert (_current_trans);
2969 assert (!_current_trans_quarks.empty ());
2974 DEBUG_UNDO_HISTORY (
2975 string_compose ("Current Undo Transaction %1, adding command: %2",
2976 _current_trans->name (),
2978 _current_trans->add_command (cmd);
2981 DEBUG_UNDO_HISTORY (
2982 string_compose ("Commit Reversible Command, current transaction: %1",
2983 _current_trans->name ()));
2985 _current_trans_quarks.pop_front ();
2987 if (!_current_trans_quarks.empty ()) {
2988 DEBUG_UNDO_HISTORY (
2989 string_compose ("Commit Reversible Command, transaction is not "
2990 "top-level, current transaction: %1",
2991 _current_trans->name ()));
2992 /* the transaction we're committing is not the top-level one */
2996 if (_current_trans->empty()) {
2997 /* no commands were added to the transaction, so just get rid of it */
2998 DEBUG_UNDO_HISTORY (
2999 string_compose ("Commit Reversible Command, No commands were "
3000 "added to current transaction: %1",
3001 _current_trans->name ()));
3002 delete _current_trans;
3007 gettimeofday (&now, 0);
3008 _current_trans->set_timestamp (now);
3010 _history.add (_current_trans);
3015 accept_all_audio_files (const string& path, void* /*arg*/)
3017 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3021 if (!AudioFileSource::safe_audio_file_extension (path)) {
3029 accept_all_midi_files (const string& path, void* /*arg*/)
3031 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3035 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3036 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3037 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3041 accept_all_state_files (const string& path, void* /*arg*/)
3043 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3047 std::string const statefile_ext (statefile_suffix);
3048 if (path.length() >= statefile_ext.length()) {
3049 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3056 Session::find_all_sources (string path, set<string>& result)
3061 if (!tree.read (path)) {
3065 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3070 XMLNodeConstIterator niter;
3072 nlist = node->children();
3076 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3078 XMLProperty const * prop;
3080 if ((prop = (*niter)->property (X_("type"))) == 0) {
3084 DataType type (prop->value());
3086 if ((prop = (*niter)->property (X_("name"))) == 0) {
3090 if (Glib::path_is_absolute (prop->value())) {
3091 /* external file, ignore */
3099 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3100 result.insert (found_path);
3108 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3110 vector<string> state_files;
3112 string this_snapshot_path;
3118 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3119 ripped = ripped.substr (0, ripped.length() - 1);
3122 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3124 if (state_files.empty()) {
3129 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3130 this_snapshot_path += statefile_suffix;
3132 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3134 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3136 if (exclude_this_snapshot && *i == this_snapshot_path) {
3137 cerr << "\texcluded\n";
3142 if (find_all_sources (*i, result) < 0) {
3150 struct RegionCounter {
3151 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3152 AudioSourceList::iterator iter;
3153 boost::shared_ptr<Region> region;
3156 RegionCounter() : count (0) {}
3160 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3162 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3163 return r.get_value_or (1);
3167 Session::cleanup_regions ()
3169 bool removed = false;
3170 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3172 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3174 uint32_t used = playlists->region_use_count (i->second);
3176 if (used == 0 && !i->second->automatic ()) {
3177 boost::weak_ptr<Region> w = i->second;
3180 RegionFactory::map_remove (w);
3187 // re-check to remove parent references of compound regions
3188 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3189 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3193 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3194 if (0 == playlists->region_use_count (i->second)) {
3195 boost::weak_ptr<Region> w = i->second;
3197 RegionFactory::map_remove (w);
3204 /* dump the history list */
3211 Session::can_cleanup_peakfiles () const
3213 if (deletion_in_progress()) {
3216 if (!_writable || (_state_of_the_state & CannotSave)) {
3217 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3220 if (record_status() == Recording) {
3221 error << _("Cannot cleanup peak-files while recording") << endmsg;
3228 Session::cleanup_peakfiles ()
3230 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3235 assert (can_cleanup_peakfiles ());
3236 assert (!peaks_cleanup_in_progres());
3238 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3240 int timeout = 5000; // 5 seconds
3241 while (!SourceFactory::files_with_peaks.empty()) {
3242 Glib::usleep (1000);
3243 if (--timeout < 0) {
3244 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3245 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3250 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3251 boost::shared_ptr<AudioSource> as;
3252 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3253 as->close_peakfile();
3257 PBD::clear_directory (session_directory().peak_path());
3259 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3261 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3262 boost::shared_ptr<AudioSource> as;
3263 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3264 SourceFactory::setup_peakfile(as, true);
3271 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3273 pl->deep_sources (*all_sources);
3277 Session::cleanup_sources (CleanupReport& rep)
3279 // FIXME: needs adaptation to midi
3281 vector<boost::shared_ptr<Source> > dead_sources;
3284 vector<string> candidates;
3285 vector<string> unused;
3286 set<string> sources_used_by_all_snapshots;
3293 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3295 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3297 /* this is mostly for windows which doesn't allow file
3298 * renaming if the file is in use. But we don't special
3299 * case it because we need to know if this causes
3300 * problems, and the easiest way to notice that is to
3301 * keep it in place for all platforms.
3304 request_stop (false);
3306 _butler->wait_until_finished ();
3308 /* consider deleting all unused playlists */
3310 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3315 /* sync the "all regions" property of each playlist with its current state */
3317 playlists->sync_all_regions_with_regions ();
3319 /* find all un-used sources */
3324 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3326 SourceMap::iterator tmp;
3331 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3335 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3336 dead_sources.push_back (i->second);
3337 i->second->drop_references ();
3343 /* build a list of all the possible audio directories for the session */
3345 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3346 SessionDirectory sdir ((*i).path);
3347 asp += sdir.sound_path();
3349 audio_path += asp.to_string();
3352 /* build a list of all the possible midi directories for the session */
3354 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3355 SessionDirectory sdir ((*i).path);
3356 msp += sdir.midi_path();
3358 midi_path += msp.to_string();
3360 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3361 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3363 /* add sources from all other snapshots as "used", but don't use this
3364 snapshot because the state file on disk still references sources we
3365 may have already dropped.
3368 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3370 /* Although the region factory has a list of all regions ever created
3371 * for this session, we're only interested in regions actually in
3372 * playlists right now. So merge all playlist regions lists together.
3374 * This will include the playlists used within compound regions.
3377 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3379 /* add our current source list
3382 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3383 boost::shared_ptr<FileSource> fs;
3384 SourceMap::iterator tmp = i;
3387 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3393 /* this is mostly for windows which doesn't allow file
3394 * renaming if the file is in use. But we do not special
3395 * case it because we need to know if this causes
3396 * problems, and the easiest way to notice that is to
3397 * keep it in place for all platforms.
3402 if (!fs->is_stub()) {
3404 /* Note that we're checking a list of all
3405 * sources across all snapshots with the list
3406 * of sources used by this snapshot.
3409 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3410 /* this source is in use by this snapshot */
3411 sources_used_by_all_snapshots.insert (fs->path());
3412 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3414 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3415 /* this source is NOT in use by this snapshot */
3417 /* remove all related regions from RegionFactory master list */
3419 RegionFactory::remove_regions_using_source (i->second);
3421 /* remove from our current source list
3422 * also. We may not remove it from
3423 * disk, because it may be used by
3424 * other snapshots, but it isn't used inside this
3425 * snapshot anymore, so we don't need a
3436 /* now check each candidate source to see if it exists in the list of
3437 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3440 cerr << "Candidates: " << candidates.size() << endl;
3441 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3443 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3448 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3450 tmppath1 = canonical_path (spath);
3451 tmppath2 = canonical_path ((*i));
3453 cerr << "\t => " << tmppath2 << endl;
3455 if (tmppath1 == tmppath2) {
3462 unused.push_back (spath);
3466 cerr << "Actually unused: " << unused.size() << endl;
3468 if (unused.empty()) {
3474 /* now try to move all unused files into the "dead" directory(ies) */
3476 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3481 /* don't move the file across filesystems, just
3482 * stick it in the `dead_dir_name' directory
3483 * on whichever filesystem it was already on.
3486 if ((*x).find ("/sounds/") != string::npos) {
3488 /* old school, go up 1 level */
3490 newpath = Glib::path_get_dirname (*x); // "sounds"
3491 newpath = Glib::path_get_dirname (newpath); // "session-name"
3495 /* new school, go up 4 levels */
3497 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3498 newpath = Glib::path_get_dirname (newpath); // "session-name"
3499 newpath = Glib::path_get_dirname (newpath); // "interchange"
3500 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3503 newpath = Glib::build_filename (newpath, dead_dir_name);
3505 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3506 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3510 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3512 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3514 /* the new path already exists, try versioning */
3516 char buf[PATH_MAX+1];
3520 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3523 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3524 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3528 if (version == 999) {
3529 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3533 newpath = newpath_v;
3538 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3539 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3540 newpath, g_strerror (errno)) << endmsg;
3544 /* see if there an easy to find peakfile for this file, and remove it. */
3546 string base = Glib::path_get_basename (*x);
3547 base += "%A"; /* this is what we add for the channel suffix of all native files,
3548 * or for the first channel of embedded files. it will miss
3549 * some peakfiles for other channels
3551 string peakpath = construct_peak_filepath (base);
3553 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3554 if (::g_unlink (peakpath.c_str ()) != 0) {
3555 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3556 g_strerror (errno)) << endmsg;
3557 /* try to back out */
3558 ::g_rename (newpath.c_str (), _path.c_str ());
3563 rep.paths.push_back (*x);
3564 rep.space += statbuf.st_size;
3567 /* dump the history list */
3571 /* save state so we don't end up a session file
3572 * referring to non-existent sources.
3579 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3585 Session::cleanup_trash_sources (CleanupReport& rep)
3587 // FIXME: needs adaptation for MIDI
3589 vector<space_and_path>::iterator i;
3595 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3597 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3599 clear_directory (dead_dir, &rep.space, &rep.paths);
3606 Session::set_dirty ()
3608 /* return early if there's nothing to do */
3613 /* never mark session dirty during loading */
3614 if (_state_of_the_state & Loading) {
3618 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3619 DirtyChanged(); /* EMIT SIGNAL */
3623 Session::set_clean ()
3625 bool was_dirty = dirty();
3627 _state_of_the_state = Clean;
3630 DirtyChanged(); /* EMIT SIGNAL */
3635 Session::set_deletion_in_progress ()
3637 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3641 Session::clear_deletion_in_progress ()
3643 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3647 Session::add_controllable (boost::shared_ptr<Controllable> c)
3649 /* this adds a controllable to the list managed by the Session.
3650 this is a subset of those managed by the Controllable class
3651 itself, and represents the only ones whose state will be saved
3652 as part of the session.
3655 Glib::Threads::Mutex::Lock lm (controllables_lock);
3656 controllables.insert (c);
3659 struct null_deleter { void operator()(void const *) const {} };
3662 Session::remove_controllable (Controllable* c)
3664 if (_state_of_the_state & Deletion) {
3668 Glib::Threads::Mutex::Lock lm (controllables_lock);
3670 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3672 if (x != controllables.end()) {
3673 controllables.erase (x);
3677 boost::shared_ptr<Controllable>
3678 Session::controllable_by_id (const PBD::ID& id)
3680 Glib::Threads::Mutex::Lock lm (controllables_lock);
3682 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3683 if ((*i)->id() == id) {
3688 return boost::shared_ptr<Controllable>();
3691 boost::shared_ptr<AutomationControl>
3692 Session::automation_control_by_id (const PBD::ID& id)
3694 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3697 boost::shared_ptr<Controllable>
3698 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3700 boost::shared_ptr<Controllable> c;
3701 boost::shared_ptr<Stripable> s;
3702 boost::shared_ptr<Route> r;
3704 switch (desc.top_level_type()) {
3705 case ControllableDescriptor::NamedRoute:
3707 std::string str = desc.top_level_name();
3709 if (str == "Master" || str == "master") {
3711 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3713 } else if (str == "auditioner") {
3716 s = route_by_name (desc.top_level_name());
3722 case ControllableDescriptor::PresentationOrderRoute:
3723 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3726 case ControllableDescriptor::PresentationOrderTrack:
3727 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3730 case ControllableDescriptor::PresentationOrderBus:
3731 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3734 case ControllableDescriptor::PresentationOrderVCA:
3735 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3738 case ControllableDescriptor::SelectionCount:
3739 s = route_by_selected_count (desc.selection_id());
3747 r = boost::dynamic_pointer_cast<Route> (s);
3749 switch (desc.subtype()) {
3750 case ControllableDescriptor::Gain:
3751 c = s->gain_control ();
3754 case ControllableDescriptor::Trim:
3755 c = s->trim_control ();
3758 case ControllableDescriptor::Solo:
3759 c = s->solo_control();
3762 case ControllableDescriptor::Mute:
3763 c = s->mute_control();
3766 case ControllableDescriptor::Recenable:
3767 c = s->rec_enable_control ();
3770 case ControllableDescriptor::PanDirection:
3771 c = s->pan_azimuth_control();
3774 case ControllableDescriptor::PanWidth:
3775 c = s->pan_width_control();
3778 case ControllableDescriptor::PanElevation:
3779 c = s->pan_elevation_control();
3782 case ControllableDescriptor::Balance:
3783 /* XXX simple pan control */
3786 case ControllableDescriptor::PluginParameter:
3788 uint32_t plugin = desc.target (0);
3789 uint32_t parameter_index = desc.target (1);
3791 /* revert to zero based counting */
3797 if (parameter_index > 0) {
3805 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3808 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3809 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3814 case ControllableDescriptor::SendGain: {
3815 uint32_t send = desc.target (0);
3822 c = r->send_level_controllable (send);
3827 /* relax and return a null pointer */
3835 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3838 Stateful::add_instant_xml (node, _path);
3841 if (write_to_config) {
3842 Config->add_instant_xml (node);
3847 Session::instant_xml (const string& node_name)
3849 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3850 if (get_disable_all_loaded_plugins ()) {
3854 return Stateful::instant_xml (node_name, _path);
3858 Session::save_history (string snapshot_name)
3866 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3867 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3871 if (snapshot_name.empty()) {
3872 snapshot_name = _current_snapshot_name;
3875 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3876 const string backup_filename = history_filename + backup_suffix;
3877 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3878 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3880 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3881 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3882 error << _("could not backup old history file, current history not saved") << endmsg;
3887 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3889 if (!tree.write (xml_path))
3891 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3893 if (g_remove (xml_path.c_str()) != 0) {
3894 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3895 xml_path, g_strerror (errno)) << endmsg;
3897 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3898 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3899 backup_path, g_strerror (errno)) << endmsg;
3909 Session::restore_history (string snapshot_name)
3913 if (snapshot_name.empty()) {
3914 snapshot_name = _current_snapshot_name;
3917 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3918 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3920 info << "Loading history from " << xml_path << endmsg;
3922 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3923 info << string_compose (_("%1: no history file \"%2\" for this session."),
3924 _name, xml_path) << endmsg;
3928 if (!tree.read (xml_path)) {
3929 error << string_compose (_("Could not understand session history file \"%1\""),
3930 xml_path) << endmsg;
3937 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3940 UndoTransaction* ut = new UndoTransaction ();
3946 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3947 !t->get_property ("tv-usec", tv_usec)) {
3951 ut->set_name (name);
3955 tv.tv_usec = tv_usec;
3956 ut->set_timestamp(tv);
3958 for (XMLNodeConstIterator child_it = t->children().begin();
3959 child_it != t->children().end(); child_it++)
3961 XMLNode *n = *child_it;
3964 if (n->name() == "MementoCommand" ||
3965 n->name() == "MementoUndoCommand" ||
3966 n->name() == "MementoRedoCommand") {
3968 if ((c = memento_command_factory(n))) {
3972 } else if (n->name() == "NoteDiffCommand") {
3973 PBD::ID id (n->property("midi-source")->value());
3974 boost::shared_ptr<MidiSource> midi_source =
3975 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3977 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3979 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3982 } else if (n->name() == "SysExDiffCommand") {
3984 PBD::ID id (n->property("midi-source")->value());
3985 boost::shared_ptr<MidiSource> midi_source =
3986 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3988 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3990 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3993 } else if (n->name() == "PatchChangeDiffCommand") {
3995 PBD::ID id (n->property("midi-source")->value());
3996 boost::shared_ptr<MidiSource> midi_source =
3997 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3999 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
4001 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
4004 } else if (n->name() == "StatefulDiffCommand") {
4005 if ((c = stateful_diff_command_factory (n))) {
4006 ut->add_command (c);
4009 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
4020 Session::config_changed (std::string p, bool ours)
4026 if (p == "seamless-loop") {
4028 } else if (p == "rf-speed") {
4030 } else if (p == "auto-loop") {
4032 } else if (p == "session-monitoring") {
4034 } else if (p == "auto-input") {
4036 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4037 /* auto-input only makes a difference if we're rolling */
4038 set_track_monitor_input_status (!config.get_auto_input());
4041 } else if (p == "punch-in") {
4045 if ((location = _locations->auto_punch_location()) != 0) {
4047 if (config.get_punch_in ()) {
4048 auto_punch_start_changed (location);
4050 clear_events (SessionEvent::PunchIn);
4054 } else if (p == "punch-out") {
4058 if ((location = _locations->auto_punch_location()) != 0) {
4060 if (config.get_punch_out()) {
4061 auto_punch_end_changed (location);
4063 clear_events (SessionEvent::PunchOut);
4067 } else if (p == "edit-mode") {
4069 Glib::Threads::Mutex::Lock lm (playlists->lock);
4071 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4072 (*i)->set_edit_mode (Config->get_edit_mode ());
4075 } else if (p == "use-video-sync") {
4077 waiting_for_sync_offset = config.get_use_video_sync();
4079 } else if (p == "mmc-control") {
4081 //poke_midi_thread ();
4083 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4085 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4087 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4089 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4091 } else if (p == "midi-control") {
4093 //poke_midi_thread ();
4095 } else if (p == "raid-path") {
4097 setup_raid_path (config.get_raid_path());
4099 } else if (p == "timecode-format") {
4103 } else if (p == "video-pullup") {
4107 } else if (p == "seamless-loop") {
4109 if (play_loop && transport_rolling()) {
4110 // to reset diskstreams etc
4111 request_play_loop (true);
4114 } else if (p == "rf-speed") {
4116 cumulative_rf_motion = 0;
4119 } else if (p == "click-sound") {
4121 setup_click_sounds (1);
4123 } else if (p == "click-emphasis-sound") {
4125 setup_click_sounds (-1);
4127 } else if (p == "clicking") {
4129 if (Config->get_clicking()) {
4130 if (_click_io && click_data) { // don't require emphasis data
4137 } else if (p == "click-record-only") {
4139 _click_rec_only = Config->get_click_record_only();
4141 } else if (p == "click-gain") {
4144 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4147 } else if (p == "send-mtc") {
4149 if (Config->get_send_mtc ()) {
4150 /* mark us ready to send */
4151 next_quarter_frame_to_send = 0;
4154 } else if (p == "send-mmc") {
4156 _mmc->enable_send (Config->get_send_mmc ());
4157 if (Config->get_send_mmc ()) {
4158 /* re-initialize MMC */
4159 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
4160 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
4163 } else if (p == "jack-time-master") {
4165 engine().reset_timebase ();
4167 } else if (p == "native-file-header-format") {
4169 if (!first_file_header_format_reset) {
4170 reset_native_file_format ();
4173 first_file_header_format_reset = false;
4175 } else if (p == "native-file-data-format") {
4177 if (!first_file_data_format_reset) {
4178 reset_native_file_format ();
4181 first_file_data_format_reset = false;
4183 } else if (p == "external-sync") {
4184 if (!config.get_external_sync()) {
4185 drop_sync_source ();
4187 switch_to_sync_source (Config->get_sync_source());
4189 } else if (p == "denormal-model") {
4191 } else if (p == "history-depth") {
4192 set_history_depth (Config->get_history_depth());
4193 } else if (p == "remote-model") {
4194 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4197 } else if (p == "initial-program-change") {
4199 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4202 buf[0] = MIDI::program; // channel zero by default
4203 buf[1] = (Config->get_initial_program_change() & 0x7f);
4205 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4207 } else if (p == "solo-mute-override") {
4208 // catch_up_on_solo_mute_override ();
4209 } else if (p == "listen-position" || p == "pfl-position") {
4210 listen_position_changed ();
4211 } else if (p == "solo-control-is-listen-control") {
4212 solo_control_mode_changed ();
4213 } else if (p == "solo-mute-gain") {
4214 _solo_cut_control->Changed (true, Controllable::NoGroup);
4215 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4216 last_timecode_valid = false;
4217 } else if (p == "playback-buffer-seconds") {
4218 AudioSource::allocate_working_buffers (sample_rate());
4219 } else if (p == "ltc-source-port") {
4220 reconnect_ltc_input ();
4221 } else if (p == "ltc-sink-port") {
4222 reconnect_ltc_output ();
4223 } else if (p == "timecode-generator-offset") {
4224 ltc_tx_parse_offset();
4225 } else if (p == "auto-return-target-list") {
4226 follow_playhead_priority ();
4233 Session::set_history_depth (uint32_t d)
4235 _history.set_depth (d);
4238 /** Connect things to the MMC object */
4240 Session::setup_midi_machine_control ()
4242 _mmc = new MIDI::MachineControl;
4244 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4245 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4247 if (!async_out || !async_out) {
4251 /* XXXX argh, passing raw pointers back into libmidi++ */
4253 MIDI::Port* mmc_in = async_in.get();
4254 MIDI::Port* mmc_out = async_out.get();
4256 _mmc->set_ports (mmc_in, mmc_out);
4258 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4259 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4260 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4261 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4262 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4263 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4264 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4265 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4266 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4267 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4268 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4269 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4270 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4272 /* also handle MIDI SPP because its so common */
4274 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4275 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4276 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4279 boost::shared_ptr<Controllable>
4280 Session::solo_cut_control() const
4282 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4283 * controls in Ardour that currently get presented to the user in the GUI that require
4284 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4286 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4287 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4290 return _solo_cut_control;
4294 Session::save_snapshot_name (const std::string & n)
4296 /* assure Stateful::_instant_xml is loaded
4297 * add_instant_xml() only adds to existing data and defaults
4298 * to use an empty Tree otherwise
4300 instant_xml ("LastUsedSnapshot");
4302 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4303 last_used_snapshot->set_property ("name", n);
4304 add_instant_xml (*last_used_snapshot, false);
4308 Session::set_snapshot_name (const std::string & n)
4310 _current_snapshot_name = n;
4311 save_snapshot_name (n);
4315 Session::rename (const std::string& new_name)
4317 string legal_name = legalize_for_path (new_name);
4323 string const old_sources_root = _session_dir->sources_root();
4325 if (!_writable || (_state_of_the_state & CannotSave)) {
4326 error << _("Cannot rename read-only session.") << endmsg;
4327 return 0; // don't show "messed up" warning
4329 if (record_status() == Recording) {
4330 error << _("Cannot rename session while recording") << endmsg;
4331 return 0; // don't show "messed up" warning
4334 StateProtector stp (this);
4339 * interchange subdirectory
4343 * Backup files are left unchanged and not renamed.
4346 /* Windows requires that we close all files before attempting the
4347 * rename. This works on other platforms, but isn't necessary there.
4348 * Leave it in place for all platforms though, since it may help
4349 * catch issues that could arise if the way Source files work ever
4350 * change (since most developers are not using Windows).
4353 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4354 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4360 /* pass one: not 100% safe check that the new directory names don't
4364 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4368 /* this is a stupid hack because Glib::path_get_dirname() is
4369 * lexical-only, and so passing it /a/b/c/ gives a different
4370 * result than passing it /a/b/c ...
4373 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4374 oldstr = oldstr.substr (0, oldstr.length() - 1);
4377 string base = Glib::path_get_dirname (oldstr);
4379 newstr = Glib::build_filename (base, legal_name);
4381 cerr << "Looking for " << newstr << endl;
4383 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4384 cerr << " exists\n";
4393 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4399 /* this is a stupid hack because Glib::path_get_dirname() is
4400 * lexical-only, and so passing it /a/b/c/ gives a different
4401 * result than passing it /a/b/c ...
4404 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4405 oldstr = oldstr.substr (0, oldstr.length() - 1);
4408 string base = Glib::path_get_dirname (oldstr);
4409 newstr = Glib::build_filename (base, legal_name);
4411 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4413 cerr << "Rename " << oldstr << " => " << newstr << endl;
4414 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4415 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4416 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4420 /* Reset path in "session dirs" */
4425 /* reset primary SessionDirectory object */
4428 (*_session_dir) = newstr;
4433 /* now rename directory below session_dir/interchange */
4435 string old_interchange_dir;
4436 string new_interchange_dir;
4438 /* use newstr here because we renamed the path
4439 * (folder/directory) that used to be oldstr to newstr above
4442 v.push_back (newstr);
4443 v.push_back (interchange_dir_name);
4444 v.push_back (Glib::path_get_basename (oldstr));
4446 old_interchange_dir = Glib::build_filename (v);
4449 v.push_back (newstr);
4450 v.push_back (interchange_dir_name);
4451 v.push_back (legal_name);
4453 new_interchange_dir = Glib::build_filename (v);
4455 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4457 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4458 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4459 old_interchange_dir, new_interchange_dir,
4462 error << string_compose (_("renaming %s as %2 failed (%3)"),
4463 old_interchange_dir, new_interchange_dir,
4472 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4473 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4475 cerr << "Rename " << oldstr << " => " << newstr << endl;
4477 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4478 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4479 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4485 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4487 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4488 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4490 cerr << "Rename " << oldstr << " => " << newstr << endl;
4492 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4493 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4494 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4499 /* remove old name from recent sessions */
4500 remove_recent_sessions (_path);
4503 /* update file source paths */
4505 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4506 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4508 string p = fs->path ();
4509 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4511 SourceFactory::setup_peakfile(i->second, true);
4515 set_snapshot_name (new_name);
4520 /* save state again to get everything just right */
4522 save_state (_current_snapshot_name);
4524 /* add to recent sessions */
4526 store_recent_sessions (new_name, _path);
4532 Session::parse_stateful_loading_version (const std::string& version)
4534 if (version.empty ()) {
4535 /* no version implies very old version of Ardour */
4539 if (version.find ('.') != string::npos) {
4540 /* old school version format */
4541 if (version[0] == '2') {
4547 return string_to<int32_t>(version);
4552 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4554 bool found_sr = false;
4555 bool found_data_format = false;
4556 std::string version;
4557 program_version = "";
4559 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4563 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4567 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4570 xmlFreeParserCtxt(ctxt);
4574 xmlNodePtr node = xmlDocGetRootElement(doc);
4577 xmlFreeParserCtxt(ctxt);
4582 /* sample rate & version*/
4585 for (attr = node->properties; attr; attr = attr->next) {
4586 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4587 version = std::string ((char*)attr->children->content);
4589 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4590 sample_rate = atoi ((char*)attr->children->content);
4595 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4599 node = node->children;
4600 while (node != NULL) {
4601 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4602 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4604 program_version = string ((const char*)val);
4605 size_t sep = program_version.find_first_of("-");
4606 if (sep != string::npos) {
4607 program_version = program_version.substr (0, sep);
4612 if (strcmp((const char*) node->name, "Config")) {
4616 for (node = node->children; node; node = node->next) {
4617 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4618 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4620 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4623 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4625 found_data_format = true;
4626 } catch (PBD::unknown_enumeration& e) {}
4636 xmlFreeParserCtxt(ctxt);
4639 return (found_sr && found_data_format) ? 0 : 1;
4643 Session::get_snapshot_from_instant (const std::string& session_dir)
4645 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4647 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4652 if (!tree.read (instant_xml_path)) {
4656 XMLProperty const * prop;
4657 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4658 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4659 return prop->value();
4665 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4666 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4669 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4673 SourcePathMap source_path_map;
4675 boost::shared_ptr<AudioFileSource> afs;
4680 Glib::Threads::Mutex::Lock lm (source_lock);
4682 cerr << " total sources = " << sources.size();
4684 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4685 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4691 if (fs->within_session()) {
4695 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4696 source_path_map[fs->path()].push_back (fs);
4698 SeveralFileSources v;
4700 source_path_map.insert (make_pair (fs->path(), v));
4706 cerr << " fsources = " << total << endl;
4708 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4710 /* tell caller where we are */
4712 string old_path = i->first;
4714 callback (n, total, old_path);
4716 cerr << old_path << endl;
4720 switch (i->second.front()->type()) {
4721 case DataType::AUDIO:
4722 new_path = new_audio_source_path_for_embedded (old_path);
4725 case DataType::MIDI:
4726 /* XXX not implemented yet */
4730 if (new_path.empty()) {
4734 cerr << "Move " << old_path << " => " << new_path << endl;
4736 if (!copy_file (old_path, new_path)) {
4737 cerr << "failed !\n";
4741 /* make sure we stop looking in the external
4742 dir/folder. Remember, this is an all-or-nothing
4743 operations, it doesn't merge just some files.
4745 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4747 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4748 (*f)->set_path (new_path);
4753 save_state ("", false, false);
4759 bool accept_all_files (string const &, void *)
4765 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4767 /* 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.
4772 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4774 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4776 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4778 v.push_back (new_session_folder); /* full path */
4779 v.push_back (interchange_dir_name);
4780 v.push_back (new_session_path); /* just one directory/folder */
4781 v.push_back (typedir);
4782 v.push_back (Glib::path_get_basename (old_path));
4784 return Glib::build_filename (v);
4788 Session::save_as (SaveAs& saveas)
4790 vector<string> files;
4791 string current_folder = Glib::path_get_dirname (_path);
4792 string new_folder = legalize_for_path (saveas.new_name);
4793 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4794 int64_t total_bytes = 0;
4798 int32_t internal_file_cnt = 0;
4800 vector<string> do_not_copy_extensions;
4801 do_not_copy_extensions.push_back (statefile_suffix);
4802 do_not_copy_extensions.push_back (pending_suffix);
4803 do_not_copy_extensions.push_back (backup_suffix);
4804 do_not_copy_extensions.push_back (temp_suffix);
4805 do_not_copy_extensions.push_back (history_suffix);
4807 /* get total size */
4809 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4811 /* need to clear this because
4812 * find_files_matching_filter() is cumulative
4817 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4819 all += files.size();
4821 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4823 g_stat ((*i).c_str(), &gsb);
4824 total_bytes += gsb.st_size;
4828 /* save old values so we can switch back if we are not switching to the new session */
4830 string old_path = _path;
4831 string old_name = _name;
4832 string old_snapshot = _current_snapshot_name;
4833 string old_sd = _session_dir->root_path();
4834 vector<string> old_search_path[DataType::num_types];
4835 string old_config_search_path[DataType::num_types];
4837 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4838 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4839 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4840 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4842 /* switch session directory */
4844 (*_session_dir) = to_dir;
4846 /* create new tree */
4848 if (!_session_dir->create()) {
4849 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4854 /* copy all relevant files. Find each location in session_dirs,
4855 * and copy files from there to target.
4858 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4860 /* need to clear this because
4861 * find_files_matching_filter() is cumulative
4866 const size_t prefix_len = (*sd).path.size();
4868 /* Work just on the files within this session dir */
4870 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4872 /* add dir separator to protect against collisions with
4873 * track names (e.g. track named "audiofiles" or
4877 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4878 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4879 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4881 /* copy all the files. Handling is different for media files
4882 than others because of the *silly* subtree we have below the interchange
4883 folder. That really was a bad idea, but I'm not fixing it as part of
4884 implementing ::save_as().
4887 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4889 std::string from = *i;
4892 string filename = Glib::path_get_basename (from);
4893 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4894 if (filename == ".DS_STORE") {
4899 if (from.find (audiofile_dir_string) != string::npos) {
4901 /* audio file: only copy if asked */
4903 if (saveas.include_media && saveas.copy_media) {
4905 string to = make_new_media_path (*i, to_dir, new_folder);
4907 info << "media file copying from " << from << " to " << to << endmsg;
4909 if (!copy_file (from, to)) {
4910 throw Glib::FileError (Glib::FileError::IO_ERROR,
4911 string_compose(_("\ncopying \"%1\" failed !"), from));
4915 /* we found media files inside the session folder */
4917 internal_file_cnt++;
4919 } else if (from.find (midifile_dir_string) != string::npos) {
4921 /* midi file: always copy unless
4922 * creating an empty new session
4925 if (saveas.include_media) {
4927 string to = make_new_media_path (*i, to_dir, new_folder);
4929 info << "media file copying from " << from << " to " << to << endmsg;
4931 if (!copy_file (from, to)) {
4932 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4936 /* we found media files inside the session folder */
4938 internal_file_cnt++;
4940 } else if (from.find (analysis_dir_string) != string::npos) {
4942 /* make sure analysis dir exists in
4943 * new session folder, but we're not
4944 * copying analysis files here, see
4948 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4953 /* normal non-media file. Don't copy state, history, etc.
4956 bool do_copy = true;
4958 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4959 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4960 /* end of filename matches extension, do not copy file */
4966 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4967 /* don't copy peakfiles if
4968 * we're not copying media
4974 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4976 info << "attempting to make directory/folder " << to << endmsg;
4978 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4979 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4982 info << "attempting to copy " << from << " to " << to << endmsg;
4984 if (!copy_file (from, to)) {
4985 throw Glib::FileError (Glib::FileError::IO_ERROR,
4986 string_compose(_("\ncopying \"%1\" failed !"), from));
4991 /* measure file size even if we're not going to copy so that our Progress
4992 signals are correct, since we included these do-not-copy files
4993 in the computation of the total size and file count.
4997 g_stat (from.c_str(), &gsb);
4998 copied += gsb.st_size;
5001 double fraction = (double) copied / total_bytes;
5003 bool keep_going = true;
5005 if (saveas.copy_media) {
5007 /* no need or expectation of this if
5008 * media is not being copied, because
5009 * it will be fast(ish).
5012 /* tell someone "X percent, file M of N"; M is one-based */
5014 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
5022 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
5028 /* copy optional folders, if any */
5030 string old = plugins_dir ();
5031 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5032 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5033 copy_files (old, newdir);
5036 old = externals_dir ();
5037 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5038 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5039 copy_files (old, newdir);
5042 old = automation_dir ();
5043 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5044 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5045 copy_files (old, newdir);
5048 if (saveas.include_media) {
5050 if (saveas.copy_media) {
5051 #ifndef PLATFORM_WINDOWS
5052 /* There are problems with analysis files on
5053 * Windows, because they used a colon in their
5054 * names as late as 4.0. Colons are not legal
5055 * under Windows even if NTFS allows them.
5057 * This is a tricky problem to solve so for
5058 * just don't copy these files. They will be
5059 * regenerated as-needed anyway, subject to the
5060 * existing issue that the filenames will be
5061 * rejected by Windows, which is a separate
5062 * problem (though related).
5065 /* only needed if we are copying media, since the
5066 * analysis data refers to media data
5069 old = analysis_dir ();
5070 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5071 string newdir = Glib::build_filename (to_dir, "analysis");
5072 copy_files (old, newdir);
5074 #endif /* PLATFORM_WINDOWS */
5079 set_snapshot_name (saveas.new_name);
5080 _name = saveas.new_name;
5082 if (saveas.include_media && !saveas.copy_media) {
5084 /* reset search paths of the new session (which we're pretending to be right now) to
5085 include the original session search path, so we can still find all audio.
5088 if (internal_file_cnt) {
5089 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5090 ensure_search_path_includes (*s, DataType::AUDIO);
5091 cerr << "be sure to include " << *s << " for audio" << endl;
5094 /* we do not do this for MIDI because we copy
5095 all MIDI files if saveas.include_media is
5101 bool was_dirty = dirty ();
5103 save_default_options ();
5105 if (saveas.copy_media && saveas.copy_external) {
5106 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5107 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5111 saveas.final_session_folder_name = _path;
5113 store_recent_sessions (_name, _path);
5115 if (!saveas.switch_to) {
5117 /* save the new state */
5119 save_state ("", false, false, !saveas.include_media);
5121 /* switch back to the way things were */
5125 set_snapshot_name (old_snapshot);
5127 (*_session_dir) = old_sd;
5133 if (internal_file_cnt) {
5134 /* reset these to their original values */
5135 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5136 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5141 /* prune session dirs, and update disk space statistics
5146 session_dirs.clear ();
5147 session_dirs.push_back (sp);
5148 refresh_disk_space ();
5150 _writable = exists_and_writable (_path);
5152 /* ensure that all existing tracks reset their current capture source paths
5154 reset_write_sources (true, true);
5156 /* creating new write sources marks the session as
5157 dirty. If the new session is empty, then
5158 save_state() thinks we're saving a template and will
5159 not mark the session as clean. So do that here,
5160 before we save state.
5163 if (!saveas.include_media) {
5164 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5167 save_state ("", false, false, !saveas.include_media);
5169 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5170 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5173 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5174 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5180 if (fs->within_session()) {
5181 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5182 fs->set_path (newpath);
5187 } catch (Glib::FileError& e) {
5189 saveas.failure_message = e.what();
5191 /* recursively remove all the directories */
5193 remove_directory (to_dir);
5201 saveas.failure_message = _("unknown reason");
5203 /* recursively remove all the directories */
5205 remove_directory (to_dir);
5215 static void set_progress (Progress* p, size_t n, size_t t)
5217 p->set_progress (float (n) / float(t));
5221 Session::archive_session (const std::string& dest,
5222 const std::string& name,
5223 ArchiveEncode compress_audio,
5224 FileArchive::CompressionLevel compression_level,
5225 bool only_used_sources,
5228 if (dest.empty () || name.empty ()) {
5232 /* save current values */
5233 bool was_dirty = dirty ();
5234 string old_path = _path;
5235 string old_name = _name;
5236 string old_snapshot = _current_snapshot_name;
5237 string old_sd = _session_dir->root_path();
5238 string old_config_search_path[DataType::num_types];
5239 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5240 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5242 /* ensure that session-path is included in search-path */
5244 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5245 if ((*sd).path == old_path) {
5253 /* create temporary dir to save session to */
5254 #ifdef PLATFORM_WINDOWS
5255 char tmp[256] = "C:\\TEMP\\";
5256 GetTempPath (sizeof (tmp), tmp);
5258 char const* tmp = getenv("TMPDIR");
5263 if ((strlen (tmp) + 21) > 1024) {
5268 strcpy (tmptpl, tmp);
5269 strcat (tmptpl, "ardourarchive-XXXXXX");
5270 char* tmpdir = g_mkdtemp (tmptpl);
5276 std::string to_dir = std::string (tmpdir);
5278 /* switch session directory temporarily */
5279 (*_session_dir) = to_dir;
5281 if (!_session_dir->create()) {
5282 (*_session_dir) = old_sd;
5283 remove_directory (to_dir);
5287 /* prepare archive */
5288 string archive = Glib::build_filename (dest, name + session_archive_suffix);
5290 PBD::ScopedConnectionList progress_connection;
5291 PBD::FileArchive ar (archive);
5293 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5296 /* collect files to archive */
5297 std::map<string,string> filemap;
5299 vector<string> do_not_copy_extensions;
5300 do_not_copy_extensions.push_back (statefile_suffix);
5301 do_not_copy_extensions.push_back (pending_suffix);
5302 do_not_copy_extensions.push_back (backup_suffix);
5303 do_not_copy_extensions.push_back (temp_suffix);
5304 do_not_copy_extensions.push_back (history_suffix);
5306 vector<string> blacklist_dirs;
5307 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5308 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5309 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5310 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5311 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5312 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5314 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5315 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5317 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5318 if (only_used_sources) {
5319 playlists->sync_all_regions_with_regions ();
5320 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5323 // collect audio sources for this session, calc total size for encoding
5324 // add option to only include *used* sources (see Session::cleanup_sources)
5325 size_t total_size = 0;
5327 Glib::Threads::Mutex::Lock lm (source_lock);
5328 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5329 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5330 if (!afs || afs->readable_length () == 0) {
5334 if (only_used_sources) {
5338 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5343 std::string from = afs->path();
5345 if (compress_audio != NO_ENCODE) {
5346 total_size += afs->readable_length ();
5348 if (afs->within_session()) {
5349 filemap[from] = make_new_media_path (from, name, name);
5351 filemap[from] = make_new_media_path (from, name, name);
5352 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5359 if (compress_audio != NO_ENCODE) {
5361 progress->set_progress (2); // set to "encoding"
5362 progress->set_progress (0);
5365 Glib::Threads::Mutex::Lock lm (source_lock);
5366 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5367 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5368 if (!afs || afs->readable_length () == 0) {
5372 if (only_used_sources) {
5376 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5381 orig_sources[afs] = afs->path();
5382 orig_gain[afs] = afs->gain();
5384 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5386 std::string channelsuffix = "";
5387 if (afs->channel() > 0) { /* n_channels() is /wrongly/ 1. */
5388 /* embedded external multi-channel files are converted to multiple-mono */
5389 channelsuffix = string_compose ("-c%1", afs->channel ());
5391 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + channelsuffix + ".flac");
5392 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5396 progress->descend ((float)afs->readable_length () / total_size);
5400 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5401 afs->replace_file (new_path);
5402 afs->set_gain (ns->gain(), true);
5405 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5409 progress->ascend ();
5415 progress->set_progress (-1); // set to "archiving"
5416 progress->set_progress (0);
5419 /* index files relevant for this session */
5420 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5421 vector<string> files;
5423 size_t prefix_len = (*sd).path.size();
5424 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5428 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5430 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5431 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5432 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5434 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5435 std::string from = *i;
5438 string filename = Glib::path_get_basename (from);
5439 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5440 if (filename == ".DS_STORE") {
5445 if (from.find (audiofile_dir_string) != string::npos) {
5447 } else if (from.find (midifile_dir_string) != string::npos) {
5448 filemap[from] = make_new_media_path (from, name, name);
5449 } else if (from.find (videofile_dir_string) != string::npos) {
5450 filemap[from] = make_new_media_path (from, name, name);
5452 bool do_copy = true;
5453 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5454 if (from.find (*v) != string::npos) {
5459 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5460 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5467 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5473 /* write session file */
5475 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5477 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5479 save_state (name, /*pending, don't fork MIDI, don't mark clean */ true);
5482 cerr << "archiving state from "
5483 << Glib::build_filename (to_dir, legalize_for_path (name) + pending_suffix)
5485 << Glib::build_filename (to_dir, legalize_for_path (name) + statefile_suffix)
5490 Glib::build_filename (to_dir, legalize_for_path (name) + pending_suffix).c_str(),
5491 Glib::build_filename (to_dir, legalize_for_path (name) + statefile_suffix).c_str());
5493 save_default_options ();
5495 size_t prefix_len = _path.size();
5496 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5500 /* collect session-state files */
5501 vector<string> files;
5502 do_not_copy_extensions.clear ();
5503 do_not_copy_extensions.push_back (history_suffix);
5505 blacklist_dirs.clear ();
5506 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5508 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5509 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5510 std::string from = *i;
5511 bool do_copy = true;
5512 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5513 if (from.find (*v) != string::npos) {
5518 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5519 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5525 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5529 /* restore original values */
5532 set_snapshot_name (old_snapshot);
5533 (*_session_dir) = old_sd;
5537 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5538 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5540 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5541 i->first->replace_file (i->second);
5543 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5544 i->first->set_gain (i->second, true);
5547 int rv = ar.create (filemap, compression_level);
5548 remove_directory (to_dir);
5554 Session::undo (uint32_t n)
5556 if (actively_recording()) {
5564 Session::redo (uint32_t n)
5566 if (actively_recording()) {