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_archive.h"
71 #include "pbd/file_utils.h"
72 #include "pbd/pathexpand.h"
73 #include "pbd/pthread_utils.h"
74 #include "pbd/stacktrace.h"
75 #include "pbd/types_convert.h"
76 #include "pbd/localtime_r.h"
77 #include "pbd/unwind.h"
79 #include "ardour/amp.h"
80 #include "ardour/async_midi_port.h"
81 #include "ardour/audio_diskstream.h"
82 #include "ardour/audio_track.h"
83 #include "ardour/audioengine.h"
84 #include "ardour/audiofilesource.h"
85 #include "ardour/audioregion.h"
86 #include "ardour/auditioner.h"
87 #include "ardour/automation_control.h"
88 #include "ardour/boost_debug.h"
89 #include "ardour/butler.h"
90 #include "ardour/controllable_descriptor.h"
91 #include "ardour/control_protocol_manager.h"
92 #include "ardour/directory_names.h"
93 #include "ardour/filename_extensions.h"
94 #include "ardour/graph.h"
95 #include "ardour/location.h"
97 #include "ardour/lv2_plugin.h"
99 #include "ardour/midi_model.h"
100 #include "ardour/midi_patch_manager.h"
101 #include "ardour/midi_region.h"
102 #include "ardour/midi_scene_changer.h"
103 #include "ardour/midi_source.h"
104 #include "ardour/midi_track.h"
105 #include "ardour/pannable.h"
106 #include "ardour/playlist_factory.h"
107 #include "ardour/playlist_source.h"
108 #include "ardour/port.h"
109 #include "ardour/processor.h"
110 #include "ardour/progress.h"
111 #include "ardour/profile.h"
112 #include "ardour/proxy_controllable.h"
113 #include "ardour/recent_sessions.h"
114 #include "ardour/region_factory.h"
115 #include "ardour/revision.h"
116 #include "ardour/route_group.h"
117 #include "ardour/send.h"
118 #include "ardour/selection.h"
119 #include "ardour/session.h"
120 #include "ardour/session_directory.h"
121 #include "ardour/session_metadata.h"
122 #include "ardour/session_playlists.h"
123 #include "ardour/session_state_utils.h"
124 #include "ardour/silentfilesource.h"
125 #include "ardour/smf_source.h"
126 #include "ardour/sndfilesource.h"
127 #include "ardour/source_factory.h"
128 #include "ardour/speakers.h"
129 #include "ardour/template_utils.h"
130 #include "ardour/tempo.h"
131 #include "ardour/ticker.h"
132 #include "ardour/types_convert.h"
133 #include "ardour/user_bundle.h"
134 #include "ardour/vca.h"
135 #include "ardour/vca_manager.h"
137 #include "control_protocol/control_protocol.h"
139 #include "LuaBridge/LuaBridge.h"
141 #include "pbd/i18n.h"
145 using namespace ARDOUR;
148 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
151 Session::pre_engine_init (string fullpath)
153 if (fullpath.empty()) {
155 throw failed_constructor();
158 /* discover canonical fullpath */
160 _path = canonical_path(fullpath);
163 if (Profile->get_trx() ) {
164 // Waves TracksLive has a usecase of session replacement with a new one.
165 // We should check session state file (<session_name>.ardour) existance
166 // to determine if the session is new or not
168 string full_session_name = Glib::build_filename( fullpath, _name );
169 full_session_name += statefile_suffix;
171 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
173 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
176 /* finish initialization that can't be done in a normal C++ constructor
180 timerclear (&last_mmc_step);
181 g_atomic_int_set (&processing_prohibited, 0);
182 g_atomic_int_set (&_record_status, Disabled);
183 g_atomic_int_set (&_playback_load, 100);
184 g_atomic_int_set (&_capture_load, 100);
186 _all_route_group->set_active (true, this);
187 interpolation.add_channel_to (0, 0);
189 if (config.get_use_video_sync()) {
190 waiting_for_sync_offset = true;
192 waiting_for_sync_offset = false;
195 last_rr_session_dir = session_dirs.begin();
197 set_history_depth (Config->get_history_depth());
199 /* default: assume simple stereo speaker configuration */
201 _speakers->setup_default_speakers (2);
203 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
204 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
205 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
206 add_controllable (_solo_cut_control);
208 /* These are all static "per-class" signals */
210 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
211 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
212 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
213 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
214 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
216 /* stop IO objects from doing stuff until we're ready for them */
218 Delivery::disable_panners ();
219 IO::disable_connecting ();
223 Session::post_engine_init ()
225 BootMessage (_("Set block size and sample rate"));
227 set_block_size (_engine.samples_per_cycle());
228 set_frame_rate (_engine.sample_rate());
230 BootMessage (_("Using configuration"));
232 _midi_ports = new MidiPortManager;
234 MIDISceneChanger* msc;
236 _scene_changer = msc = new MIDISceneChanger (*this);
237 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
238 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
240 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
241 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
243 setup_midi_machine_control ();
245 if (_butler->start_thread()) {
246 error << _("Butler did not start") << endmsg;
250 if (start_midi_thread ()) {
251 error << _("MIDI I/O thread did not start") << endmsg;
255 setup_click_sounds (0);
256 setup_midi_control ();
258 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
259 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
262 /* tempo map requires sample rate knowledge */
265 _tempo_map = new TempoMap (_current_frame_rate);
266 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
267 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
268 } catch (std::exception const & e) {
269 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
272 error << _("Unknown exception during session setup") << endmsg;
277 /* MidiClock requires a tempo map */
280 midi_clock = new MidiClockTicker ();
281 midi_clock->set_session (this);
283 /* crossfades require sample rate knowledge */
285 SndFileSource::setup_standard_crossfades (*this, frame_rate());
286 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
287 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
289 AudioDiskstream::allocate_working_buffers();
290 refresh_disk_space ();
292 /* we're finally ready to call set_state() ... all objects have
293 * 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;
302 // set_state() will call setup_raid_path(), but if it's a new session we need
303 // to call setup_raid_path() here.
304 setup_raid_path (_path);
309 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
310 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
312 Config->map_parameters (ff);
313 config.map_parameters (ft);
314 _butler->map_parameters ();
316 /* Reset all panners */
318 Delivery::reset_panners ();
320 /* this will cause the CPM to instantiate any protocols that are in use
321 * (or mandatory), which will pass it this Session, and then call
322 * set_state() on each instantiated protocol to match stored state.
325 ControlProtocolManager::instance().set_session (this);
327 /* This must be done after the ControlProtocolManager set_session above,
328 as it will set states for ports which the ControlProtocolManager creates.
331 // XXX set state of MIDI::Port's
332 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
334 /* And this must be done after the MIDI::Manager::set_port_states as
335 * it will try to make connections whose details are loaded by set_port_states.
340 /* Let control protocols know that we are now all connected, so they
341 * could start talking to surfaces if they want to.
344 ControlProtocolManager::instance().midi_connectivity_established ();
346 if (_is_new && !no_auto_connect()) {
347 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
348 auto_connect_master_bus ();
351 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
353 /* update latencies */
355 initialize_latencies ();
357 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
358 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
359 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
361 } catch (AudioEngine::PortRegistrationFailure& err) {
362 error << err.what() << endmsg;
364 } catch (std::exception const & e) {
365 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
368 error << _("Unknown exception during session setup") << endmsg;
372 BootMessage (_("Reset Remote Controls"));
374 // send_full_time_code (0);
375 _engine.transport_locate (0);
377 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
378 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
380 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
383 /* initial program change will be delivered later; see ::config_changed() */
385 _state_of_the_state = Clean;
387 Port::set_connecting_blocked (false);
389 DirtyChanged (); /* EMIT SIGNAL */
393 } else if (state_was_pending) {
395 remove_pending_capture_state ();
396 state_was_pending = false;
399 /* Now, finally, we can fill the playback buffers */
401 BootMessage (_("Filling playback buffers"));
403 boost::shared_ptr<RouteList> rl = routes.reader();
404 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
405 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
406 if (trk && !trk->hidden()) {
407 trk->seek (_transport_frame, true);
415 Session::session_loaded ()
419 _state_of_the_state = Clean;
421 DirtyChanged (); /* EMIT SIGNAL */
425 } else if (state_was_pending) {
427 remove_pending_capture_state ();
428 state_was_pending = false;
431 /* Now, finally, we can fill the playback buffers */
433 BootMessage (_("Filling playback buffers"));
434 force_locate (_transport_frame, false);
438 Session::raid_path () const
440 Searchpath raid_search_path;
442 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
443 raid_search_path += (*i).path;
446 return raid_search_path.to_string ();
450 Session::setup_raid_path (string path)
459 session_dirs.clear ();
461 Searchpath search_path(path);
462 Searchpath sound_search_path;
463 Searchpath midi_search_path;
465 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
467 sp.blocks = 0; // not needed
468 session_dirs.push_back (sp);
470 SessionDirectory sdir(sp.path);
472 sound_search_path += sdir.sound_path ();
473 midi_search_path += sdir.midi_path ();
476 // reset the round-robin soundfile path thingie
477 last_rr_session_dir = session_dirs.begin();
481 Session::path_is_within_session (const std::string& path)
483 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
484 if (PBD::path_is_within (i->path, path)) {
492 Session::ensure_subdirs ()
496 dir = session_directory().peak_path();
498 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
499 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
503 dir = session_directory().sound_path();
505 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
506 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
510 dir = session_directory().midi_path();
512 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
513 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
517 dir = session_directory().dead_path();
519 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
520 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
524 dir = session_directory().export_path();
526 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
527 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
531 dir = analysis_dir ();
533 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
534 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
538 dir = plugins_dir ();
540 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
541 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
545 dir = externals_dir ();
547 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
548 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
555 /** @param session_template directory containing session template, or empty.
556 * Caller must not hold process lock.
559 Session::create (const string& session_template, BusProfile* bus_profile)
561 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
562 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
566 if (ensure_subdirs ()) {
570 _writable = exists_and_writable (_path);
572 if (!session_template.empty()) {
573 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
575 FILE* in = g_fopen (in_path.c_str(), "rb");
578 /* no need to call legalize_for_path() since the string
579 * in session_template is already a legal path name
581 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
583 FILE* out = g_fopen (out_path.c_str(), "wb");
587 stringstream new_session;
590 size_t charsRead = fread (buf, sizeof(char), 1024, in);
593 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
598 if (charsRead == 0) {
601 new_session.write (buf, charsRead);
605 string file_contents = new_session.str();
606 size_t writeSize = file_contents.length();
607 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
608 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
616 if (!ARDOUR::Profile->get_trx()) {
617 /* Copy plugin state files from template to new session */
618 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
619 copy_recurse (template_plugins, plugins_dir ());
625 error << string_compose (_("Could not open %1 for writing session template"), out_path)
632 error << string_compose (_("Could not open session template %1 for reading"), in_path)
639 if (Profile->get_trx()) {
641 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
642 * Remember that this is a brand new session. Sessions
643 * loaded from saved state will get this range from the saved state.
646 set_session_range_location (0, 0);
648 /* Initial loop location, from absolute zero, length 10 seconds */
650 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
651 _locations->add (loc, true);
652 set_auto_loop_location (loc);
655 _state_of_the_state = Clean;
657 /* set up Master Out and Monitor Out if necessary */
661 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
663 // Waves Tracks: always create master bus for Tracks
664 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
665 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
673 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
674 r->input()->ensure_io (count, false, this);
675 r->output()->ensure_io (count, false, this);
683 add_routes (rl, false, false, false, PresentationInfo::max_order);
687 if (Config->get_use_monitor_bus() && bus_profile) {
688 add_monitor_section ();
695 Session::maybe_write_autosave()
697 if (dirty() && record_status() != Recording) {
698 save_state("", true);
703 Session::remove_pending_capture_state ()
705 std::string pending_state_file_path(_session_dir->root_path());
707 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
709 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
711 if (g_remove (pending_state_file_path.c_str()) != 0) {
712 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
713 pending_state_file_path, g_strerror (errno)) << endmsg;
717 /** Rename a state file.
718 * @param old_name Old snapshot name.
719 * @param new_name New snapshot name.
722 Session::rename_state (string old_name, string new_name)
724 if (old_name == _current_snapshot_name || old_name == _name) {
725 /* refuse to rename the current snapshot or the "main" one */
729 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
730 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
732 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
733 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
735 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
736 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
737 old_name, new_name, g_strerror(errno)) << endmsg;
741 /** Remove a state file.
742 * @param snapshot_name Snapshot name.
745 Session::remove_state (string snapshot_name)
747 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
748 // refuse to remove the current snapshot or the "main" one
752 std::string xml_path(_session_dir->root_path());
754 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
756 if (!create_backup_file (xml_path)) {
757 // don't remove it if a backup can't be made
758 // create_backup_file will log the error.
763 if (g_remove (xml_path.c_str()) != 0) {
764 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
765 xml_path, g_strerror (errno)) << endmsg;
769 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
771 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
773 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
776 std::string xml_path(_session_dir->root_path());
778 /* prevent concurrent saves from different threads */
780 Glib::Threads::Mutex::Lock lm (save_state_lock);
782 if (!_writable || (_state_of_the_state & CannotSave)) {
786 if (g_atomic_int_get(&_suspend_save)) {
790 _save_queued = false;
792 snapshot_t fork_state = NormalSave;
793 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) {
794 /* snapshot, close midi */
795 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
799 const int64_t save_start_time = g_get_monotonic_time();
802 /* tell sources we're saving first, in case they write out to a new file
803 * which should be saved with the state rather than the old one */
804 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
806 i->second->session_saved();
807 } catch (Evoral::SMF::FileError& e) {
808 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
812 SessionSaveUnderway (); /* EMIT SIGNAL */
814 bool mark_as_clean = true;
816 if (!snapshot_name.empty() && !switch_to_snapshot) {
817 mark_as_clean = false;
821 mark_as_clean = false;
822 tree.set_root (&get_template());
824 tree.set_root (&state (true, fork_state));
827 if (snapshot_name.empty()) {
828 snapshot_name = _current_snapshot_name;
829 } else if (switch_to_snapshot) {
830 set_snapshot_name (snapshot_name);
833 assert (!snapshot_name.empty());
837 /* proper save: use statefile_suffix (.ardour in English) */
839 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
841 /* make a backup copy of the old file */
843 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
844 // create_backup_file will log the error
850 /* pending save: use pending_suffix (.pending in English) */
851 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
854 std::string tmp_path(_session_dir->root_path());
855 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
857 cerr << "actually writing state to " << tmp_path << endl;
859 if (!tree.write (tmp_path)) {
860 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
861 if (g_remove (tmp_path.c_str()) != 0) {
862 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
863 tmp_path, g_strerror (errno)) << endmsg;
869 cerr << "renaming state to " << xml_path << endl;
871 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
872 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
873 tmp_path, xml_path, g_strerror(errno)) << endmsg;
874 if (g_remove (tmp_path.c_str()) != 0) {
875 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
876 tmp_path, g_strerror (errno)) << endmsg;
884 save_history (snapshot_name);
887 bool was_dirty = dirty();
889 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
892 DirtyChanged (); /* EMIT SIGNAL */
896 StateSaved (snapshot_name); /* EMIT SIGNAL */
900 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
901 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
907 Session::restore_state (string snapshot_name)
909 if (load_state (snapshot_name) == 0) {
910 set_state (*state_tree->root(), Stateful::loading_state_version);
917 Session::load_state (string snapshot_name)
922 state_was_pending = false;
924 /* check for leftover pending state from a crashed capture attempt */
926 std::string xmlpath(_session_dir->root_path());
927 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
929 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
931 /* there is pending state from a crashed capture attempt */
933 boost::optional<int> r = AskAboutPendingState();
934 if (r.get_value_or (1)) {
935 state_was_pending = true;
939 if (!state_was_pending) {
940 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
943 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
944 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
945 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
946 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
951 state_tree = new XMLTree;
955 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
957 if (!state_tree->read (xmlpath)) {
958 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
964 XMLNode const & root (*state_tree->root());
966 if (root.name() != X_("Session")) {
967 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
974 if (root.get_property ("version", version)) {
975 if (version.find ('.') != string::npos) {
976 /* old school version format */
977 if (version[0] == '2') {
978 Stateful::loading_state_version = 2000;
980 Stateful::loading_state_version = 3000;
983 Stateful::loading_state_version = string_to<int32_t>(version);
986 /* no version implies very old version of Ardour */
987 Stateful::loading_state_version = 1000;
990 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
992 std::string backup_path(_session_dir->root_path());
993 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
994 backup_path = Glib::build_filename (backup_path, backup_filename);
996 // only create a backup for a given statefile version once
998 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1000 VersionMismatch (xmlpath, backup_path);
1002 if (!copy_file (xmlpath, backup_path)) {;
1008 save_snapshot_name (snapshot_name);
1014 Session::load_options (const XMLNode& node)
1016 config.set_variables (node);
1021 Session::save_default_options ()
1023 return config.save_state();
1027 Session::get_state()
1033 Session::get_template()
1035 /* if we don't disable rec-enable, diskstreams
1036 will believe they need to store their capture
1037 sources in their state node.
1040 disable_record (false);
1042 return state(false);
1045 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1046 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1049 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1051 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1054 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1058 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1061 XMLNode* node = new XMLNode("TrackState"); // XXX
1064 PlaylistSet playlists; // SessionPlaylists
1067 // these will work with new_route_from_template()
1068 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1069 child = node->add_child ("Routes");
1070 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1071 if ((*i)->is_auditioner()) {
1074 if ((*i)->is_master() || (*i)->is_monitor()) {
1077 child->add_child_nocopy ((*i)->get_state());
1078 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1080 playlists.insert (track->playlist ());
1084 // on load, Regions in the playlists need to resolve and map Source-IDs
1085 // also playlist needs to be merged or created with new-name..
1086 // ... and Diskstream in tracks adjusted to use the correct playlist
1087 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1088 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1089 child->add_child_nocopy ((*i)->get_state ());
1090 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1091 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1092 const Region::SourceList& sl = (*s)->sources ();
1093 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1094 sources.insert (*sli);
1099 child = node->add_child ("Sources");
1100 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1101 child->add_child_nocopy ((*i)->get_state ());
1102 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1104 #ifdef PLATFORM_WINDOWS
1107 string p = fs->path ();
1108 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1112 std::string sn = Glib::build_filename (path, "share.axml");
1115 tree.set_root (node);
1116 return tree.write (sn.c_str());
1121 struct route_id_compare {
1123 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1125 return r1->id () < r2->id ();
1131 Session::state (bool full_state, snapshot_t snapshot_type)
1134 XMLNode* node = new XMLNode("Session");
1137 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1139 child = node->add_child ("ProgramVersion");
1140 child->set_property("created-with", created_with);
1142 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1143 child->set_property("modified-with", modified_with);
1145 /* store configuration settings */
1149 node->set_property ("name", _name);
1150 node->set_property ("sample-rate", _base_frame_rate);
1152 if (session_dirs.size() > 1) {
1156 vector<space_and_path>::iterator i = session_dirs.begin();
1157 vector<space_and_path>::iterator next;
1159 ++i; /* skip the first one */
1163 while (i != session_dirs.end()) {
1167 if (next != session_dirs.end()) {
1168 p += G_SEARCHPATH_SEPARATOR;
1177 child = node->add_child ("Path");
1178 child->add_content (p);
1180 node->set_property ("end-is-free", _session_range_end_is_free);
1183 /* save the ID counter */
1185 node->set_property ("id-counter", ID::counter());
1187 node->set_property ("name-counter", name_id_counter ());
1189 /* save the event ID counter */
1191 node->set_property ("event-counter", Evoral::event_id_counter());
1193 /* save the VCA counter */
1195 node->set_property ("vca-counter", VCA::get_next_vca_number());
1197 /* various options */
1199 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1200 if (!midi_port_nodes.empty()) {
1201 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1202 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1203 midi_port_stuff->add_child_nocopy (**n);
1205 node->add_child_nocopy (*midi_port_stuff);
1208 XMLNode& cfgxml (config.get_variables ());
1210 /* exclude search-paths from template */
1211 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1212 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1213 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1215 node->add_child_nocopy (cfgxml);
1217 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1219 child = node->add_child ("Sources");
1222 Glib::Threads::Mutex::Lock sl (source_lock);
1224 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1226 /* Don't save information about non-file Sources, or
1227 * about non-destructive file sources that are empty
1228 * and unused by any regions.
1230 boost::shared_ptr<FileSource> fs;
1232 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1236 if (!fs->destructive()) {
1237 if (fs->empty() && !fs->used()) {
1242 if (snapshot_type != NormalSave && fs->within_session ()) {
1243 /* copy MIDI sources to new file
1245 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1246 * because the GUI (midi_region) has a direct pointer to the midi-model
1247 * of the source, as does UndoTransaction.
1249 * On the upside, .mid files are not kept open. The file is only open
1250 * when reading the model initially and when flushing the model to disk:
1251 * source->session_saved () or export.
1253 * We can change the _path of the existing source under the hood, keeping
1254 * all IDs, references and pointers intact.
1256 boost::shared_ptr<SMFSource> ms;
1257 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1258 const std::string ancestor_name = ms->ancestor_name();
1259 const std::string base = PBD::basename_nosuffix(ancestor_name);
1260 const string path = new_midi_source_path (base, false);
1262 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1263 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1264 Source::Lock lm (ms->mutex());
1266 // TODO special-case empty, removable() files: just create a new removable.
1267 // (load + write flushes the model and creates the file)
1269 ms->load_model (lm);
1271 if (ms->write_to (lm, newsrc, Evoral::MinBeats, Evoral::MaxBeats)) {
1272 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1274 if (snapshot_type == SnapshotKeep) {
1275 /* keep working on current session.
1277 * Save snapshot-state with the original filename.
1278 * Switch to use new path for future saves of the main session.
1280 child->add_child_nocopy (ms->get_state());
1284 * ~SMFSource unlinks removable() files.
1286 std::string npath (ms->path ());
1287 ms->replace_file (newsrc->path ());
1288 newsrc->replace_file (npath);
1290 if (snapshot_type == SwitchToSnapshot) {
1291 /* save and switch to snapshot.
1293 * Leave the old file in place (as is).
1294 * Snapshot uses new source directly
1296 child->add_child_nocopy (ms->get_state());
1303 child->add_child_nocopy (siter->second->get_state());
1307 child = node->add_child ("Regions");
1310 Glib::Threads::Mutex::Lock rl (region_lock);
1311 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1312 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1313 boost::shared_ptr<Region> r = i->second;
1314 /* only store regions not attached to playlists */
1315 if (r->playlist() == 0) {
1316 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1317 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1319 child->add_child_nocopy (r->get_state ());
1324 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1326 if (!cassocs.empty()) {
1327 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1329 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1330 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1331 can->set_property (X_("copy"), i->first->id());
1332 can->set_property (X_("original"), i->second->id());
1333 ca->add_child_nocopy (*can);
1340 node->add_child_nocopy (_selection->get_state());
1343 node->add_child_nocopy (_locations->get_state());
1346 Locations loc (*this);
1347 const bool was_dirty = dirty();
1348 // for a template, just create a new Locations, populate it
1349 // with the default start and end, and get the state for that.
1350 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1351 range->set (max_framepos, 0);
1353 XMLNode& locations_state = loc.get_state();
1355 if (ARDOUR::Profile->get_trx() && _locations) {
1356 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1357 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1358 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1359 locations_state.add_child_nocopy ((*i)->get_state ());
1363 node->add_child_nocopy (locations_state);
1365 /* adding a location above will have marked the session
1366 * dirty. This is an artifact, so fix it if the session wasn't
1371 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1375 child = node->add_child ("Bundles");
1377 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1378 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1379 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1381 child->add_child_nocopy (b->get_state());
1386 node->add_child_nocopy (_vca_manager->get_state());
1388 child = node->add_child ("Routes");
1390 boost::shared_ptr<RouteList> r = routes.reader ();
1392 route_id_compare cmp;
1393 RouteList xml_node_order (*r);
1394 xml_node_order.sort (cmp);
1396 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1397 if (!(*i)->is_auditioner()) {
1399 child->add_child_nocopy ((*i)->get_state());
1401 child->add_child_nocopy ((*i)->get_template());
1407 playlists->add_state (node, full_state);
1409 child = node->add_child ("RouteGroups");
1410 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1411 child->add_child_nocopy ((*i)->get_state());
1415 XMLNode* gain_child = node->add_child ("Click");
1416 gain_child->add_child_nocopy (_click_io->state (full_state));
1417 gain_child->add_child_nocopy (_click_gain->state (full_state));
1421 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1422 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1426 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1427 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1430 node->add_child_nocopy (_speakers->get_state());
1431 node->add_child_nocopy (_tempo_map->get_state());
1432 node->add_child_nocopy (get_control_protocol_state());
1435 node->add_child_copy (*_extra_xml);
1439 Glib::Threads::Mutex::Lock lm (lua_lock);
1442 luabridge::LuaRef savedstate ((*_lua_save)());
1443 saved = savedstate.cast<std::string>();
1445 lua.collect_garbage ();
1448 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1449 std::string b64s (b64);
1452 XMLNode* script_node = new XMLNode (X_("Script"));
1453 script_node->set_property (X_("lua"), LUA_VERSION);
1454 script_node->add_content (b64s);
1455 node->add_child_nocopy (*script_node);
1462 Session::get_control_protocol_state ()
1464 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1465 return cpm.get_state();
1469 Session::set_state (const XMLNode& node, int version)
1476 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1478 if (node.name() != X_("Session")) {
1479 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1483 node.get_property ("name", _name);
1485 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1487 _nominal_frame_rate = _base_frame_rate;
1489 assert (AudioEngine::instance()->running ());
1490 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1491 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1492 if (r.get_value_or (0)) {
1498 created_with = "unknown";
1499 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1500 child->get_property (X_("created-with"), created_with);
1503 setup_raid_path(_session_dir->root_path());
1505 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1508 if (node.get_property (X_("id-counter"), counter)) {
1509 ID::init_counter (counter);
1511 /* old sessions used a timebased counter, so fake
1512 * the startup ID counter based on a standard
1517 ID::init_counter (now);
1520 if (node.get_property (X_("name-counter"), counter)) {
1521 init_name_id_counter (counter);
1524 if (node.get_property (X_("event-counter"), counter)) {
1525 Evoral::init_event_id_counter (counter);
1528 if (node.get_property (X_("vca-counter"), counter)) {
1529 VCA::set_next_vca_number (counter);
1531 VCA::set_next_vca_number (1);
1534 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1535 _midi_ports->set_midi_port_states (child->children());
1538 IO::disable_connecting ();
1540 Stateful::save_extra_xml (node);
1542 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1543 load_options (*child);
1544 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1545 load_options (*child);
1547 error << _("Session: XML state has no options section") << endmsg;
1550 if (version >= 3000) {
1551 if ((child = find_named_node (node, "Metadata")) == 0) {
1552 warning << _("Session: XML state has no metadata section") << endmsg;
1553 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1558 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1559 _speakers->set_state (*child, version);
1562 if ((child = find_named_node (node, "Sources")) == 0) {
1563 error << _("Session: XML state has no sources section") << endmsg;
1565 } else if (load_sources (*child)) {
1569 if ((child = find_named_node (node, "TempoMap")) == 0) {
1570 error << _("Session: XML state has no Tempo Map section") << endmsg;
1572 } else if (_tempo_map->set_state (*child, version)) {
1576 if ((child = find_named_node (node, "Locations")) == 0) {
1577 error << _("Session: XML state has no locations section") << endmsg;
1579 } else if (_locations->set_state (*child, version)) {
1583 locations_changed ();
1585 if (_session_range_location) {
1586 AudioFileSource::set_header_position_offset (_session_range_location->start());
1589 if ((child = find_named_node (node, "Regions")) == 0) {
1590 error << _("Session: XML state has no Regions section") << endmsg;
1592 } else if (load_regions (*child)) {
1596 if ((child = find_named_node (node, "Playlists")) == 0) {
1597 error << _("Session: XML state has no playlists section") << endmsg;
1599 } else if (playlists->load (*this, *child)) {
1603 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1605 } else if (playlists->load_unused (*this, *child)) {
1609 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1610 if (load_compounds (*child)) {
1615 if (version >= 3000) {
1616 if ((child = find_named_node (node, "Bundles")) == 0) {
1617 warning << _("Session: XML state has no bundles section") << endmsg;
1620 /* We can't load Bundles yet as they need to be able
1621 * to convert from port names to Port objects, which can't happen until
1623 _bundle_xml_node = new XMLNode (*child);
1627 if (version < 3000) {
1628 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1629 error << _("Session: XML state has no diskstreams section") << endmsg;
1631 } else if (load_diskstreams_2X (*child, version)) {
1636 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1637 _vca_manager->set_state (*child, version);
1640 if ((child = find_named_node (node, "Routes")) == 0) {
1641 error << _("Session: XML state has no routes section") << endmsg;
1643 } else if (load_routes (*child, version)) {
1647 /* Now that we have Routes and masters loaded, connect them if appropriate */
1649 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1651 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1652 _diskstreams_2X.clear ();
1654 if (version >= 3000) {
1656 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1657 error << _("Session: XML state has no route groups section") << endmsg;
1659 } else if (load_route_groups (*child, version)) {
1663 } else if (version < 3000) {
1665 if ((child = find_named_node (node, "EditGroups")) == 0) {
1666 error << _("Session: XML state has no edit groups section") << endmsg;
1668 } else if (load_route_groups (*child, version)) {
1672 if ((child = find_named_node (node, "MixGroups")) == 0) {
1673 error << _("Session: XML state has no mix groups section") << endmsg;
1675 } else if (load_route_groups (*child, version)) {
1680 if ((child = find_named_node (node, "Click")) == 0) {
1681 warning << _("Session: XML state has no click section") << endmsg;
1682 } else if (_click_io) {
1683 setup_click_state (&node);
1686 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1687 ControlProtocolManager::instance().set_state (*child, version);
1690 if ((child = find_named_node (node, "Script"))) {
1691 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1692 if (!(*n)->is_content ()) { continue; }
1694 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1696 Glib::Threads::Mutex::Lock lm (lua_lock);
1697 (*_lua_load)(std::string ((const char*)buf, size));
1698 } catch (luabridge::LuaException const& e) {
1699 cerr << "LuaException:" << e.what () << endl;
1705 if ((child = find_named_node (node, X_("Selection")))) {
1706 _selection->set_state (*child, version);
1709 update_route_record_state ();
1711 /* here beginneth the second phase ... */
1712 set_snapshot_name (_current_snapshot_name);
1714 StateReady (); /* EMIT SIGNAL */
1727 Session::load_routes (const XMLNode& node, int version)
1730 XMLNodeConstIterator niter;
1731 RouteList new_routes;
1733 nlist = node.children();
1737 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1739 boost::shared_ptr<Route> route;
1740 if (version < 3000) {
1741 route = XMLRouteFactory_2X (**niter, version);
1743 route = XMLRouteFactory (**niter, version);
1747 error << _("Session: cannot create Route from XML description.") << endmsg;
1751 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1753 new_routes.push_back (route);
1756 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1758 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1760 BootMessage (_("Finished adding tracks/busses"));
1765 boost::shared_ptr<Route>
1766 Session::XMLRouteFactory (const XMLNode& node, int version)
1768 boost::shared_ptr<Route> ret;
1770 if (node.name() != "Route") {
1774 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1776 DataType type = DataType::AUDIO;
1777 node.get_property("default-type", type);
1779 assert (type != DataType::NIL);
1783 boost::shared_ptr<Track> track;
1785 if (type == DataType::AUDIO) {
1786 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1788 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1791 if (track->init()) {
1795 if (track->set_state (node, version)) {
1799 BOOST_MARK_TRACK (track);
1803 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1804 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1806 if (r->init () == 0 && r->set_state (node, version) == 0) {
1807 BOOST_MARK_ROUTE (r);
1815 boost::shared_ptr<Route>
1816 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1818 boost::shared_ptr<Route> ret;
1820 if (node.name() != "Route") {
1824 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1826 ds_prop = node.property (X_("diskstream"));
1829 DataType type = DataType::AUDIO;
1830 node.get_property("default-type", type);
1832 assert (type != DataType::NIL);
1836 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1837 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1841 if (i == _diskstreams_2X.end()) {
1842 error << _("Could not find diskstream for route") << endmsg;
1843 return boost::shared_ptr<Route> ();
1846 boost::shared_ptr<Track> track;
1848 if (type == DataType::AUDIO) {
1849 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1851 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1854 if (track->init()) {
1858 if (track->set_state (node, version)) {
1862 track->set_diskstream (*i);
1864 BOOST_MARK_TRACK (track);
1868 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1869 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1871 if (r->init () == 0 && r->set_state (node, version) == 0) {
1872 BOOST_MARK_ROUTE (r);
1881 Session::load_regions (const XMLNode& node)
1884 XMLNodeConstIterator niter;
1885 boost::shared_ptr<Region> region;
1887 nlist = node.children();
1891 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1892 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1893 error << _("Session: cannot create Region from XML description.");
1894 XMLProperty const * name = (**niter).property("name");
1897 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1908 Session::load_compounds (const XMLNode& node)
1910 XMLNodeList calist = node.children();
1911 XMLNodeConstIterator caiter;
1912 XMLProperty const * caprop;
1914 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1915 XMLNode* ca = *caiter;
1919 if ((caprop = ca->property (X_("original"))) == 0) {
1922 orig_id = caprop->value();
1924 if ((caprop = ca->property (X_("copy"))) == 0) {
1927 copy_id = caprop->value();
1929 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1930 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1932 if (!orig || !copy) {
1933 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1939 RegionFactory::add_compound_association (orig, copy);
1946 Session::load_nested_sources (const XMLNode& node)
1949 XMLNodeConstIterator niter;
1951 nlist = node.children();
1953 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1954 if ((*niter)->name() == "Source") {
1956 /* it may already exist, so don't recreate it unnecessarily
1959 XMLProperty const * prop = (*niter)->property (X_("id"));
1961 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1965 ID source_id (prop->value());
1967 if (!source_by_id (source_id)) {
1970 SourceFactory::create (*this, **niter, true);
1972 catch (failed_constructor& err) {
1973 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1980 boost::shared_ptr<Region>
1981 Session::XMLRegionFactory (const XMLNode& node, bool full)
1983 XMLProperty const * type = node.property("type");
1987 const XMLNodeList& nlist = node.children();
1989 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1990 XMLNode *child = (*niter);
1991 if (child->name() == "NestedSource") {
1992 load_nested_sources (*child);
1996 if (!type || type->value() == "audio") {
1997 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1998 } else if (type->value() == "midi") {
1999 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2002 } catch (failed_constructor& err) {
2003 return boost::shared_ptr<Region> ();
2006 return boost::shared_ptr<Region> ();
2009 boost::shared_ptr<AudioRegion>
2010 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2012 XMLProperty const * prop;
2013 boost::shared_ptr<Source> source;
2014 boost::shared_ptr<AudioSource> as;
2016 SourceList master_sources;
2017 uint32_t nchans = 1;
2020 if (node.name() != X_("Region")) {
2021 return boost::shared_ptr<AudioRegion>();
2024 node.get_property (X_("channels"), nchans);
2026 if ((prop = node.property ("name")) == 0) {
2027 cerr << "no name for this region\n";
2031 if ((prop = node.property (X_("source-0"))) == 0) {
2032 if ((prop = node.property ("source")) == 0) {
2033 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2034 return boost::shared_ptr<AudioRegion>();
2038 PBD::ID s_id (prop->value());
2040 if ((source = source_by_id (s_id)) == 0) {
2041 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2042 return boost::shared_ptr<AudioRegion>();
2045 as = boost::dynamic_pointer_cast<AudioSource>(source);
2047 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2048 return boost::shared_ptr<AudioRegion>();
2051 sources.push_back (as);
2053 /* pickup other channels */
2055 for (uint32_t n=1; n < nchans; ++n) {
2056 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2057 if ((prop = node.property (buf)) != 0) {
2059 PBD::ID id2 (prop->value());
2061 if ((source = source_by_id (id2)) == 0) {
2062 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2063 return boost::shared_ptr<AudioRegion>();
2066 as = boost::dynamic_pointer_cast<AudioSource>(source);
2068 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2069 return boost::shared_ptr<AudioRegion>();
2071 sources.push_back (as);
2075 for (uint32_t n = 0; n < nchans; ++n) {
2076 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2077 if ((prop = node.property (buf)) != 0) {
2079 PBD::ID id2 (prop->value());
2081 if ((source = source_by_id (id2)) == 0) {
2082 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2083 return boost::shared_ptr<AudioRegion>();
2086 as = boost::dynamic_pointer_cast<AudioSource>(source);
2088 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2089 return boost::shared_ptr<AudioRegion>();
2091 master_sources.push_back (as);
2096 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2098 /* a final detail: this is the one and only place that we know how long missing files are */
2100 if (region->whole_file()) {
2101 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2102 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2104 sfp->set_length (region->length());
2109 if (!master_sources.empty()) {
2110 if (master_sources.size() != nchans) {
2111 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2113 region->set_master_sources (master_sources);
2121 catch (failed_constructor& err) {
2122 return boost::shared_ptr<AudioRegion>();
2126 boost::shared_ptr<MidiRegion>
2127 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2129 XMLProperty const * prop;
2130 boost::shared_ptr<Source> source;
2131 boost::shared_ptr<MidiSource> ms;
2134 if (node.name() != X_("Region")) {
2135 return boost::shared_ptr<MidiRegion>();
2138 if ((prop = node.property ("name")) == 0) {
2139 cerr << "no name for this region\n";
2143 if ((prop = node.property (X_("source-0"))) == 0) {
2144 if ((prop = node.property ("source")) == 0) {
2145 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2146 return boost::shared_ptr<MidiRegion>();
2150 PBD::ID s_id (prop->value());
2152 if ((source = source_by_id (s_id)) == 0) {
2153 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2154 return boost::shared_ptr<MidiRegion>();
2157 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2159 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2160 return boost::shared_ptr<MidiRegion>();
2163 sources.push_back (ms);
2166 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2167 /* a final detail: this is the one and only place that we know how long missing files are */
2169 if (region->whole_file()) {
2170 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2171 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2173 sfp->set_length (region->length());
2181 catch (failed_constructor& err) {
2182 return boost::shared_ptr<MidiRegion>();
2187 Session::get_sources_as_xml ()
2190 XMLNode* node = new XMLNode (X_("Sources"));
2191 Glib::Threads::Mutex::Lock lm (source_lock);
2193 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2194 node->add_child_nocopy (i->second->get_state());
2201 Session::reset_write_sources (bool mark_write_complete, bool force)
2203 boost::shared_ptr<RouteList> rl = routes.reader();
2204 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2205 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2207 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2208 tr->reset_write_sources(mark_write_complete, force);
2209 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2215 Session::load_sources (const XMLNode& node)
2218 XMLNodeConstIterator niter;
2219 /* don't need this but it stops some
2220 * versions of gcc complaining about
2221 * discarded return values.
2223 boost::shared_ptr<Source> source;
2225 nlist = node.children();
2228 std::map<std::string, std::string> relocation;
2230 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2231 #ifdef PLATFORM_WINDOWS
2235 XMLNode srcnode (**niter);
2236 bool try_replace_abspath = true;
2240 #ifdef PLATFORM_WINDOWS
2241 // do not show "insert media" popups (files embedded from removable media).
2242 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2244 if ((source = XMLSourceFactory (srcnode)) == 0) {
2245 error << _("Session: cannot create Source from XML description.") << endmsg;
2247 #ifdef PLATFORM_WINDOWS
2248 SetErrorMode(old_mode);
2251 } catch (MissingSource& err) {
2252 #ifdef PLATFORM_WINDOWS
2253 SetErrorMode(old_mode);
2256 /* try previous abs path replacements first */
2257 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2258 std::string dir = Glib::path_get_dirname (err.path);
2259 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2260 if (rl != relocation.end ()) {
2261 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2262 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2263 srcnode.set_property ("origin", newpath);
2264 try_replace_abspath = false;
2271 _missing_file_replacement = "";
2273 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2274 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2275 PROGRAM_NAME) << endmsg;
2279 if (!no_questions_about_missing_files) {
2280 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2285 switch (user_choice) {
2287 /* user added a new search location
2288 * or selected a new absolute path,
2290 if (Glib::path_is_absolute (err.path)) {
2291 if (!_missing_file_replacement.empty ()) {
2292 /* replace origin, in XML */
2293 std::string newpath = Glib::build_filename (
2294 _missing_file_replacement, Glib::path_get_basename (err.path));
2295 srcnode.set_property ("origin", newpath);
2296 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2297 _missing_file_replacement = "";
2304 /* user asked to quit the entire session load */
2308 no_questions_about_missing_files = true;
2312 no_questions_about_missing_files = true;
2319 case DataType::AUDIO:
2320 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2323 case DataType::MIDI:
2324 /* The MIDI file is actually missing so
2325 * just create a new one in the same
2326 * location. Do not announce its
2330 if (!Glib::path_is_absolute (err.path)) {
2331 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2333 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2338 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2339 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2340 /* reset ID to match the missing one */
2341 source->set_id (**niter);
2342 /* Now we can announce it */
2343 SourceFactory::SourceCreated (source);
2354 boost::shared_ptr<Source>
2355 Session::XMLSourceFactory (const XMLNode& node)
2357 if (node.name() != "Source") {
2358 return boost::shared_ptr<Source>();
2362 /* note: do peak building in another thread when loading session state */
2363 return SourceFactory::create (*this, node, true);
2366 catch (failed_constructor& err) {
2367 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2368 return boost::shared_ptr<Source>();
2373 Session::save_template (string template_name, bool replace_existing)
2375 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2379 bool absolute_path = Glib::path_is_absolute (template_name);
2381 /* directory to put the template in */
2382 std::string template_dir_path;
2384 if (!absolute_path) {
2385 std::string user_template_dir(user_template_directory());
2387 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2388 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2389 user_template_dir, g_strerror (errno)) << endmsg;
2393 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2395 template_dir_path = template_name;
2398 if (!ARDOUR::Profile->get_trx()) {
2399 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2400 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2401 template_dir_path) << endmsg;
2405 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2406 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2407 template_dir_path, g_strerror (errno)) << endmsg;
2413 std::string template_file_path;
2415 if (ARDOUR::Profile->get_trx()) {
2416 template_file_path = template_name;
2418 if (absolute_path) {
2419 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2421 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2425 SessionSaveUnderway (); /* EMIT SIGNAL */
2430 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2431 tree.set_root (&get_template());
2434 if (!tree.write (template_file_path)) {
2435 error << _("template not saved") << endmsg;
2439 store_recent_templates (template_file_path);
2445 Session::refresh_disk_space ()
2447 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2449 Glib::Threads::Mutex::Lock lm (space_lock);
2451 /* get freespace on every FS that is part of the session path */
2453 _total_free_4k_blocks = 0;
2454 _total_free_4k_blocks_uncertain = false;
2456 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2457 #if defined(__NetBSD__)
2458 struct statvfs statfsbuf;
2460 statvfs (i->path.c_str(), &statfsbuf);
2462 struct statfs statfsbuf;
2464 statfs (i->path.c_str(), &statfsbuf);
2466 double const scale = statfsbuf.f_bsize / 4096.0;
2468 /* See if this filesystem is read-only */
2469 struct statvfs statvfsbuf;
2470 statvfs (i->path.c_str(), &statvfsbuf);
2472 /* f_bavail can be 0 if it is undefined for whatever
2473 filesystem we are looking at; Samba shares mounted
2474 via GVFS are an example of this.
2476 if (statfsbuf.f_bavail == 0) {
2477 /* block count unknown */
2479 i->blocks_unknown = true;
2480 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2481 /* read-only filesystem */
2483 i->blocks_unknown = false;
2485 /* read/write filesystem with known space */
2486 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2487 i->blocks_unknown = false;
2490 _total_free_4k_blocks += i->blocks;
2491 if (i->blocks_unknown) {
2492 _total_free_4k_blocks_uncertain = true;
2495 #elif defined PLATFORM_WINDOWS
2496 vector<string> scanned_volumes;
2497 vector<string>::iterator j;
2498 vector<space_and_path>::iterator i;
2499 DWORD nSectorsPerCluster, nBytesPerSector,
2500 nFreeClusters, nTotalClusters;
2504 _total_free_4k_blocks = 0;
2506 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2507 strncpy (disk_drive, (*i).path.c_str(), 3);
2511 volume_found = false;
2512 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2514 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2515 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2516 i->blocks = (uint32_t)(nFreeBytes / 4096);
2518 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2519 if (0 == j->compare(disk_drive)) {
2520 volume_found = true;
2525 if (!volume_found) {
2526 scanned_volumes.push_back(disk_drive);
2527 _total_free_4k_blocks += i->blocks;
2532 if (0 == _total_free_4k_blocks) {
2533 strncpy (disk_drive, path().c_str(), 3);
2536 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2538 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2539 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2540 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2547 Session::get_best_session_directory_for_new_audio ()
2549 vector<space_and_path>::iterator i;
2550 string result = _session_dir->root_path();
2552 /* handle common case without system calls */
2554 if (session_dirs.size() == 1) {
2558 /* OK, here's the algorithm we're following here:
2560 We want to select which directory to use for
2561 the next file source to be created. Ideally,
2562 we'd like to use a round-robin process so as to
2563 get maximum performance benefits from splitting
2564 the files across multiple disks.
2566 However, in situations without much diskspace, an
2567 RR approach may end up filling up a filesystem
2568 with new files while others still have space.
2569 Its therefore important to pay some attention to
2570 the freespace in the filesystem holding each
2571 directory as well. However, if we did that by
2572 itself, we'd keep creating new files in the file
2573 system with the most space until it was as full
2574 as all others, thus negating any performance
2575 benefits of this RAID-1 like approach.
2577 So, we use a user-configurable space threshold. If
2578 there are at least 2 filesystems with more than this
2579 much space available, we use RR selection between them.
2580 If not, then we pick the filesystem with the most space.
2582 This gets a good balance between the two
2586 refresh_disk_space ();
2588 int free_enough = 0;
2590 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2591 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2596 if (free_enough >= 2) {
2597 /* use RR selection process, ensuring that the one
2601 i = last_rr_session_dir;
2604 if (++i == session_dirs.end()) {
2605 i = session_dirs.begin();
2608 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2609 SessionDirectory sdir(i->path);
2610 if (sdir.create ()) {
2612 last_rr_session_dir = i;
2617 } while (i != last_rr_session_dir);
2621 /* pick FS with the most freespace (and that
2622 seems to actually work ...)
2625 vector<space_and_path> sorted;
2626 space_and_path_ascending_cmp cmp;
2628 sorted = session_dirs;
2629 sort (sorted.begin(), sorted.end(), cmp);
2631 for (i = sorted.begin(); i != sorted.end(); ++i) {
2632 SessionDirectory sdir(i->path);
2633 if (sdir.create ()) {
2635 last_rr_session_dir = i;
2645 Session::automation_dir () const
2647 return Glib::build_filename (_path, automation_dir_name);
2651 Session::analysis_dir () const
2653 return Glib::build_filename (_path, analysis_dir_name);
2657 Session::plugins_dir () const
2659 return Glib::build_filename (_path, plugins_dir_name);
2663 Session::externals_dir () const
2665 return Glib::build_filename (_path, externals_dir_name);
2669 Session::load_bundles (XMLNode const & node)
2671 XMLNodeList nlist = node.children();
2672 XMLNodeConstIterator niter;
2676 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2677 if ((*niter)->name() == "InputBundle") {
2678 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2679 } else if ((*niter)->name() == "OutputBundle") {
2680 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2682 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2691 Session::load_route_groups (const XMLNode& node, int version)
2693 XMLNodeList nlist = node.children();
2694 XMLNodeConstIterator niter;
2698 if (version >= 3000) {
2700 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2701 if ((*niter)->name() == "RouteGroup") {
2702 RouteGroup* rg = new RouteGroup (*this, "");
2703 add_route_group (rg);
2704 rg->set_state (**niter, version);
2708 } else if (version < 3000) {
2710 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2711 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2712 RouteGroup* rg = new RouteGroup (*this, "");
2713 add_route_group (rg);
2714 rg->set_state (**niter, version);
2723 state_file_filter (const string &str, void* /*arg*/)
2725 return (str.length() > strlen(statefile_suffix) &&
2726 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2730 remove_end(string state)
2732 string statename(state);
2734 string::size_type start,end;
2735 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2736 statename = statename.substr (start+1);
2739 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2740 end = statename.length();
2743 return string(statename.substr (0, end));
2747 Session::possible_states (string path)
2749 vector<string> states;
2750 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2752 transform(states.begin(), states.end(), states.begin(), remove_end);
2754 sort (states.begin(), states.end());
2760 Session::possible_states () const
2762 return possible_states(_path);
2766 Session::new_route_group (const std::string& name)
2768 RouteGroup* rg = NULL;
2770 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2771 if ((*i)->name () == name) {
2778 rg = new RouteGroup (*this, name);
2779 add_route_group (rg);
2785 Session::add_route_group (RouteGroup* g)
2787 _route_groups.push_back (g);
2788 route_group_added (g); /* EMIT SIGNAL */
2790 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2791 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2792 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2798 Session::remove_route_group (RouteGroup& rg)
2800 list<RouteGroup*>::iterator i;
2802 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2803 _route_groups.erase (i);
2806 route_group_removed (); /* EMIT SIGNAL */
2810 /** Set a new order for our route groups, without adding or removing any.
2811 * @param groups Route group list in the new order.
2814 Session::reorder_route_groups (list<RouteGroup*> groups)
2816 _route_groups = groups;
2818 route_groups_reordered (); /* EMIT SIGNAL */
2824 Session::route_group_by_name (string name)
2826 list<RouteGroup *>::iterator i;
2828 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2829 if ((*i)->name() == name) {
2837 Session::all_route_group() const
2839 return *_all_route_group;
2843 Session::add_commands (vector<Command*> const & cmds)
2845 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2851 Session::add_command (Command* const cmd)
2853 assert (_current_trans);
2854 DEBUG_UNDO_HISTORY (
2855 string_compose ("Current Undo Transaction %1, adding command: %2",
2856 _current_trans->name (),
2858 _current_trans->add_command (cmd);
2861 PBD::StatefulDiffCommand*
2862 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2864 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2870 Session::begin_reversible_command (const string& name)
2872 begin_reversible_command (g_quark_from_string (name.c_str ()));
2875 /** Begin a reversible command using a GQuark to identify it.
2876 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2877 * but there must be as many begin...()s as there are commit...()s.
2880 Session::begin_reversible_command (GQuark q)
2882 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2883 to hold all the commands that are committed. This keeps the order of
2884 commands correct in the history.
2887 if (_current_trans == 0) {
2888 DEBUG_UNDO_HISTORY (string_compose (
2889 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2891 /* start a new transaction */
2892 assert (_current_trans_quarks.empty ());
2893 _current_trans = new UndoTransaction();
2894 _current_trans->set_name (g_quark_to_string (q));
2896 DEBUG_UNDO_HISTORY (
2897 string_compose ("Begin Reversible Command, current transaction: %1",
2898 _current_trans->name ()));
2901 _current_trans_quarks.push_front (q);
2905 Session::abort_reversible_command ()
2907 if (_current_trans != 0) {
2908 DEBUG_UNDO_HISTORY (
2909 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2910 _current_trans->clear();
2911 delete _current_trans;
2913 _current_trans_quarks.clear();
2918 Session::commit_reversible_command (Command *cmd)
2920 assert (_current_trans);
2921 assert (!_current_trans_quarks.empty ());
2926 DEBUG_UNDO_HISTORY (
2927 string_compose ("Current Undo Transaction %1, adding command: %2",
2928 _current_trans->name (),
2930 _current_trans->add_command (cmd);
2933 DEBUG_UNDO_HISTORY (
2934 string_compose ("Commit Reversible Command, current transaction: %1",
2935 _current_trans->name ()));
2937 _current_trans_quarks.pop_front ();
2939 if (!_current_trans_quarks.empty ()) {
2940 DEBUG_UNDO_HISTORY (
2941 string_compose ("Commit Reversible Command, transaction is not "
2942 "top-level, current transaction: %1",
2943 _current_trans->name ()));
2944 /* the transaction we're committing is not the top-level one */
2948 if (_current_trans->empty()) {
2949 /* no commands were added to the transaction, so just get rid of it */
2950 DEBUG_UNDO_HISTORY (
2951 string_compose ("Commit Reversible Command, No commands were "
2952 "added to current transaction: %1",
2953 _current_trans->name ()));
2954 delete _current_trans;
2959 gettimeofday (&now, 0);
2960 _current_trans->set_timestamp (now);
2962 _history.add (_current_trans);
2967 accept_all_audio_files (const string& path, void* /*arg*/)
2969 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2973 if (!AudioFileSource::safe_audio_file_extension (path)) {
2981 accept_all_midi_files (const string& path, void* /*arg*/)
2983 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2987 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
2988 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
2989 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2993 accept_all_state_files (const string& path, void* /*arg*/)
2995 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2999 std::string const statefile_ext (statefile_suffix);
3000 if (path.length() >= statefile_ext.length()) {
3001 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3008 Session::find_all_sources (string path, set<string>& result)
3013 if (!tree.read (path)) {
3017 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3022 XMLNodeConstIterator niter;
3024 nlist = node->children();
3028 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3030 XMLProperty const * prop;
3032 if ((prop = (*niter)->property (X_("type"))) == 0) {
3036 DataType type (prop->value());
3038 if ((prop = (*niter)->property (X_("name"))) == 0) {
3042 if (Glib::path_is_absolute (prop->value())) {
3043 /* external file, ignore */
3051 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3052 result.insert (found_path);
3060 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3062 vector<string> state_files;
3064 string this_snapshot_path;
3070 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3071 ripped = ripped.substr (0, ripped.length() - 1);
3074 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3076 if (state_files.empty()) {
3081 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3082 this_snapshot_path += statefile_suffix;
3084 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3086 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3088 if (exclude_this_snapshot && *i == this_snapshot_path) {
3089 cerr << "\texcluded\n";
3094 if (find_all_sources (*i, result) < 0) {
3102 struct RegionCounter {
3103 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3104 AudioSourceList::iterator iter;
3105 boost::shared_ptr<Region> region;
3108 RegionCounter() : count (0) {}
3112 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3114 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3115 return r.get_value_or (1);
3119 Session::cleanup_regions ()
3121 bool removed = false;
3122 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3124 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3126 uint32_t used = playlists->region_use_count (i->second);
3128 if (used == 0 && !i->second->automatic ()) {
3129 boost::weak_ptr<Region> w = i->second;
3132 RegionFactory::map_remove (w);
3139 // re-check to remove parent references of compound regions
3140 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3141 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3145 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3146 if (0 == playlists->region_use_count (i->second)) {
3147 boost::weak_ptr<Region> w = i->second;
3149 RegionFactory::map_remove (w);
3156 /* dump the history list */
3163 Session::can_cleanup_peakfiles () const
3165 if (deletion_in_progress()) {
3168 if (!_writable || (_state_of_the_state & CannotSave)) {
3169 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3172 if (record_status() == Recording) {
3173 error << _("Cannot cleanup peak-files while recording") << endmsg;
3180 Session::cleanup_peakfiles ()
3182 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3187 assert (can_cleanup_peakfiles ());
3188 assert (!peaks_cleanup_in_progres());
3190 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3192 int timeout = 5000; // 5 seconds
3193 while (!SourceFactory::files_with_peaks.empty()) {
3194 Glib::usleep (1000);
3195 if (--timeout < 0) {
3196 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3197 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3202 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3203 boost::shared_ptr<AudioSource> as;
3204 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3205 as->close_peakfile();
3209 PBD::clear_directory (session_directory().peak_path());
3211 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3213 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3214 boost::shared_ptr<AudioSource> as;
3215 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3216 SourceFactory::setup_peakfile(as, true);
3223 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3225 pl->deep_sources (*all_sources);
3229 Session::cleanup_sources (CleanupReport& rep)
3231 // FIXME: needs adaptation to midi
3233 vector<boost::shared_ptr<Source> > dead_sources;
3236 vector<string> candidates;
3237 vector<string> unused;
3238 set<string> sources_used_by_all_snapshots;
3245 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3247 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3249 /* this is mostly for windows which doesn't allow file
3250 * renaming if the file is in use. But we don't special
3251 * case it because we need to know if this causes
3252 * problems, and the easiest way to notice that is to
3253 * keep it in place for all platforms.
3256 request_stop (false);
3258 _butler->wait_until_finished ();
3260 /* consider deleting all unused playlists */
3262 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3267 /* sync the "all regions" property of each playlist with its current state */
3269 playlists->sync_all_regions_with_regions ();
3271 /* find all un-used sources */
3276 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3278 SourceMap::iterator tmp;
3283 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3287 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3288 dead_sources.push_back (i->second);
3289 i->second->drop_references ();
3295 /* build a list of all the possible audio directories for the session */
3297 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3298 SessionDirectory sdir ((*i).path);
3299 asp += sdir.sound_path();
3301 audio_path += asp.to_string();
3304 /* build a list of all the possible midi directories for the session */
3306 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3307 SessionDirectory sdir ((*i).path);
3308 msp += sdir.midi_path();
3310 midi_path += msp.to_string();
3312 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3313 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3315 /* add sources from all other snapshots as "used", but don't use this
3316 snapshot because the state file on disk still references sources we
3317 may have already dropped.
3320 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3322 /* Although the region factory has a list of all regions ever created
3323 * for this session, we're only interested in regions actually in
3324 * playlists right now. So merge all playlist regions lists together.
3326 * This will include the playlists used within compound regions.
3329 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3331 /* add our current source list
3334 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3335 boost::shared_ptr<FileSource> fs;
3336 SourceMap::iterator tmp = i;
3339 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3345 /* this is mostly for windows which doesn't allow file
3346 * renaming if the file is in use. But we do not special
3347 * case it because we need to know if this causes
3348 * problems, and the easiest way to notice that is to
3349 * keep it in place for all platforms.
3354 if (!fs->is_stub()) {
3356 /* Note that we're checking a list of all
3357 * sources across all snapshots with the list
3358 * of sources used by this snapshot.
3361 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3362 /* this source is in use by this snapshot */
3363 sources_used_by_all_snapshots.insert (fs->path());
3364 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3366 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3367 /* this source is NOT in use by this snapshot */
3369 /* remove all related regions from RegionFactory master list */
3371 RegionFactory::remove_regions_using_source (i->second);
3373 /* remove from our current source list
3374 * also. We may not remove it from
3375 * disk, because it may be used by
3376 * other snapshots, but it isn't used inside this
3377 * snapshot anymore, so we don't need a
3388 /* now check each candidate source to see if it exists in the list of
3389 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3392 cerr << "Candidates: " << candidates.size() << endl;
3393 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3395 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3400 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3402 tmppath1 = canonical_path (spath);
3403 tmppath2 = canonical_path ((*i));
3405 cerr << "\t => " << tmppath2 << endl;
3407 if (tmppath1 == tmppath2) {
3414 unused.push_back (spath);
3418 cerr << "Actually unused: " << unused.size() << endl;
3420 if (unused.empty()) {
3426 /* now try to move all unused files into the "dead" directory(ies) */
3428 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3433 /* don't move the file across filesystems, just
3434 * stick it in the `dead_dir_name' directory
3435 * on whichever filesystem it was already on.
3438 if ((*x).find ("/sounds/") != string::npos) {
3440 /* old school, go up 1 level */
3442 newpath = Glib::path_get_dirname (*x); // "sounds"
3443 newpath = Glib::path_get_dirname (newpath); // "session-name"
3447 /* new school, go up 4 levels */
3449 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3450 newpath = Glib::path_get_dirname (newpath); // "session-name"
3451 newpath = Glib::path_get_dirname (newpath); // "interchange"
3452 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3455 newpath = Glib::build_filename (newpath, dead_dir_name);
3457 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3458 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3462 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3464 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3466 /* the new path already exists, try versioning */
3468 char buf[PATH_MAX+1];
3472 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3475 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3476 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3480 if (version == 999) {
3481 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3485 newpath = newpath_v;
3490 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3491 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3492 newpath, g_strerror (errno)) << endmsg;
3496 /* see if there an easy to find peakfile for this file, and remove it. */
3498 string base = Glib::path_get_basename (*x);
3499 base += "%A"; /* this is what we add for the channel suffix of all native files,
3500 * or for the first channel of embedded files. it will miss
3501 * some peakfiles for other channels
3503 string peakpath = construct_peak_filepath (base);
3505 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3506 if (::g_unlink (peakpath.c_str ()) != 0) {
3507 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3508 g_strerror (errno)) << endmsg;
3509 /* try to back out */
3510 ::g_rename (newpath.c_str (), _path.c_str ());
3515 rep.paths.push_back (*x);
3516 rep.space += statbuf.st_size;
3519 /* dump the history list */
3523 /* save state so we don't end up a session file
3524 * referring to non-existent sources.
3531 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3537 Session::cleanup_trash_sources (CleanupReport& rep)
3539 // FIXME: needs adaptation for MIDI
3541 vector<space_and_path>::iterator i;
3547 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3549 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3551 clear_directory (dead_dir, &rep.space, &rep.paths);
3558 Session::set_dirty ()
3560 /* return early if there's nothing to do */
3565 /* never mark session dirty during loading */
3566 if (_state_of_the_state & Loading) {
3570 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3571 DirtyChanged(); /* EMIT SIGNAL */
3575 Session::set_clean ()
3577 bool was_dirty = dirty();
3579 _state_of_the_state = Clean;
3582 DirtyChanged(); /* EMIT SIGNAL */
3587 Session::set_deletion_in_progress ()
3589 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3593 Session::clear_deletion_in_progress ()
3595 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3599 Session::add_controllable (boost::shared_ptr<Controllable> c)
3601 /* this adds a controllable to the list managed by the Session.
3602 this is a subset of those managed by the Controllable class
3603 itself, and represents the only ones whose state will be saved
3604 as part of the session.
3607 Glib::Threads::Mutex::Lock lm (controllables_lock);
3608 controllables.insert (c);
3611 struct null_deleter { void operator()(void const *) const {} };
3614 Session::remove_controllable (Controllable* c)
3616 if (_state_of_the_state & Deletion) {
3620 Glib::Threads::Mutex::Lock lm (controllables_lock);
3622 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3624 if (x != controllables.end()) {
3625 controllables.erase (x);
3629 boost::shared_ptr<Controllable>
3630 Session::controllable_by_id (const PBD::ID& id)
3632 Glib::Threads::Mutex::Lock lm (controllables_lock);
3634 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3635 if ((*i)->id() == id) {
3640 return boost::shared_ptr<Controllable>();
3643 boost::shared_ptr<AutomationControl>
3644 Session::automation_control_by_id (const PBD::ID& id)
3646 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3649 boost::shared_ptr<Controllable>
3650 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3652 boost::shared_ptr<Controllable> c;
3653 boost::shared_ptr<Stripable> s;
3654 boost::shared_ptr<Route> r;
3656 switch (desc.top_level_type()) {
3657 case ControllableDescriptor::NamedRoute:
3659 std::string str = desc.top_level_name();
3661 if (str == "Master" || str == "master") {
3663 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3665 } else if (str == "auditioner") {
3668 s = route_by_name (desc.top_level_name());
3674 case ControllableDescriptor::PresentationOrderRoute:
3675 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3678 case ControllableDescriptor::PresentationOrderTrack:
3679 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3682 case ControllableDescriptor::PresentationOrderBus:
3683 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3686 case ControllableDescriptor::PresentationOrderVCA:
3687 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3690 case ControllableDescriptor::SelectionCount:
3691 s = route_by_selected_count (desc.selection_id());
3699 r = boost::dynamic_pointer_cast<Route> (s);
3701 switch (desc.subtype()) {
3702 case ControllableDescriptor::Gain:
3703 c = s->gain_control ();
3706 case ControllableDescriptor::Trim:
3707 c = s->trim_control ();
3710 case ControllableDescriptor::Solo:
3711 c = s->solo_control();
3714 case ControllableDescriptor::Mute:
3715 c = s->mute_control();
3718 case ControllableDescriptor::Recenable:
3719 c = s->rec_enable_control ();
3722 case ControllableDescriptor::PanDirection:
3723 c = s->pan_azimuth_control();
3726 case ControllableDescriptor::PanWidth:
3727 c = s->pan_width_control();
3730 case ControllableDescriptor::PanElevation:
3731 c = s->pan_elevation_control();
3734 case ControllableDescriptor::Balance:
3735 /* XXX simple pan control */
3738 case ControllableDescriptor::PluginParameter:
3740 uint32_t plugin = desc.target (0);
3741 uint32_t parameter_index = desc.target (1);
3743 /* revert to zero based counting */
3749 if (parameter_index > 0) {
3757 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3760 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3761 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3766 case ControllableDescriptor::SendGain: {
3767 uint32_t send = desc.target (0);
3774 c = r->send_level_controllable (send);
3779 /* relax and return a null pointer */
3787 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3790 Stateful::add_instant_xml (node, _path);
3793 if (write_to_config) {
3794 Config->add_instant_xml (node);
3799 Session::instant_xml (const string& node_name)
3801 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3802 if (get_disable_all_loaded_plugins ()) {
3806 return Stateful::instant_xml (node_name, _path);
3810 Session::save_history (string snapshot_name)
3818 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3819 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3823 if (snapshot_name.empty()) {
3824 snapshot_name = _current_snapshot_name;
3827 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3828 const string backup_filename = history_filename + backup_suffix;
3829 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3830 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3832 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3833 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3834 error << _("could not backup old history file, current history not saved") << endmsg;
3839 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3841 if (!tree.write (xml_path))
3843 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3845 if (g_remove (xml_path.c_str()) != 0) {
3846 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3847 xml_path, g_strerror (errno)) << endmsg;
3849 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3850 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3851 backup_path, g_strerror (errno)) << endmsg;
3861 Session::restore_history (string snapshot_name)
3865 if (snapshot_name.empty()) {
3866 snapshot_name = _current_snapshot_name;
3869 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3870 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3872 info << "Loading history from " << xml_path << endmsg;
3874 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3875 info << string_compose (_("%1: no history file \"%2\" for this session."),
3876 _name, xml_path) << endmsg;
3880 if (!tree.read (xml_path)) {
3881 error << string_compose (_("Could not understand session history file \"%1\""),
3882 xml_path) << endmsg;
3889 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3892 UndoTransaction* ut = new UndoTransaction ();
3898 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3899 !t->get_property ("tv-usec", tv_usec)) {
3903 ut->set_name (name);
3907 tv.tv_usec = tv_usec;
3908 ut->set_timestamp(tv);
3910 for (XMLNodeConstIterator child_it = t->children().begin();
3911 child_it != t->children().end(); child_it++)
3913 XMLNode *n = *child_it;
3916 if (n->name() == "MementoCommand" ||
3917 n->name() == "MementoUndoCommand" ||
3918 n->name() == "MementoRedoCommand") {
3920 if ((c = memento_command_factory(n))) {
3924 } else if (n->name() == "NoteDiffCommand") {
3925 PBD::ID id (n->property("midi-source")->value());
3926 boost::shared_ptr<MidiSource> midi_source =
3927 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3929 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3931 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3934 } else if (n->name() == "SysExDiffCommand") {
3936 PBD::ID id (n->property("midi-source")->value());
3937 boost::shared_ptr<MidiSource> midi_source =
3938 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3940 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3942 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3945 } else if (n->name() == "PatchChangeDiffCommand") {
3947 PBD::ID id (n->property("midi-source")->value());
3948 boost::shared_ptr<MidiSource> midi_source =
3949 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3951 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3953 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3956 } else if (n->name() == "StatefulDiffCommand") {
3957 if ((c = stateful_diff_command_factory (n))) {
3958 ut->add_command (c);
3961 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3972 Session::config_changed (std::string p, bool ours)
3978 if (p == "seamless-loop") {
3980 } else if (p == "rf-speed") {
3982 } else if (p == "auto-loop") {
3984 } else if (p == "session-monitoring") {
3986 } else if (p == "auto-input") {
3988 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3989 /* auto-input only makes a difference if we're rolling */
3990 set_track_monitor_input_status (!config.get_auto_input());
3993 } else if (p == "punch-in") {
3997 if ((location = _locations->auto_punch_location()) != 0) {
3999 if (config.get_punch_in ()) {
4000 replace_event (SessionEvent::PunchIn, location->start());
4002 remove_event (location->start(), SessionEvent::PunchIn);
4006 } else if (p == "punch-out") {
4010 if ((location = _locations->auto_punch_location()) != 0) {
4012 if (config.get_punch_out()) {
4013 replace_event (SessionEvent::PunchOut, location->end());
4015 clear_events (SessionEvent::PunchOut);
4019 } else if (p == "edit-mode") {
4021 Glib::Threads::Mutex::Lock lm (playlists->lock);
4023 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4024 (*i)->set_edit_mode (Config->get_edit_mode ());
4027 } else if (p == "use-video-sync") {
4029 waiting_for_sync_offset = config.get_use_video_sync();
4031 } else if (p == "mmc-control") {
4033 //poke_midi_thread ();
4035 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4037 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4039 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4041 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4043 } else if (p == "midi-control") {
4045 //poke_midi_thread ();
4047 } else if (p == "raid-path") {
4049 setup_raid_path (config.get_raid_path());
4051 } else if (p == "timecode-format") {
4055 } else if (p == "video-pullup") {
4059 } else if (p == "seamless-loop") {
4061 if (play_loop && transport_rolling()) {
4062 // to reset diskstreams etc
4063 request_play_loop (true);
4066 } else if (p == "rf-speed") {
4068 cumulative_rf_motion = 0;
4071 } else if (p == "click-sound") {
4073 setup_click_sounds (1);
4075 } else if (p == "click-emphasis-sound") {
4077 setup_click_sounds (-1);
4079 } else if (p == "clicking") {
4081 if (Config->get_clicking()) {
4082 if (_click_io && click_data) { // don't require emphasis data
4089 } else if (p == "click-record-only") {
4091 _click_rec_only = Config->get_click_record_only();
4093 } else if (p == "click-gain") {
4096 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4099 } else if (p == "send-mtc") {
4101 if (Config->get_send_mtc ()) {
4102 /* mark us ready to send */
4103 next_quarter_frame_to_send = 0;
4106 } else if (p == "send-mmc") {
4108 _mmc->enable_send (Config->get_send_mmc ());
4110 } else if (p == "jack-time-master") {
4112 engine().reset_timebase ();
4114 } else if (p == "native-file-header-format") {
4116 if (!first_file_header_format_reset) {
4117 reset_native_file_format ();
4120 first_file_header_format_reset = false;
4122 } else if (p == "native-file-data-format") {
4124 if (!first_file_data_format_reset) {
4125 reset_native_file_format ();
4128 first_file_data_format_reset = false;
4130 } else if (p == "external-sync") {
4131 if (!config.get_external_sync()) {
4132 drop_sync_source ();
4134 switch_to_sync_source (Config->get_sync_source());
4136 } else if (p == "denormal-model") {
4138 } else if (p == "history-depth") {
4139 set_history_depth (Config->get_history_depth());
4140 } else if (p == "remote-model") {
4141 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4144 } else if (p == "initial-program-change") {
4146 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4149 buf[0] = MIDI::program; // channel zero by default
4150 buf[1] = (Config->get_initial_program_change() & 0x7f);
4152 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4154 } else if (p == "solo-mute-override") {
4155 // catch_up_on_solo_mute_override ();
4156 } else if (p == "listen-position" || p == "pfl-position") {
4157 listen_position_changed ();
4158 } else if (p == "solo-control-is-listen-control") {
4159 solo_control_mode_changed ();
4160 } else if (p == "solo-mute-gain") {
4161 _solo_cut_control->Changed (true, Controllable::NoGroup);
4162 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4163 last_timecode_valid = false;
4164 } else if (p == "playback-buffer-seconds") {
4165 AudioSource::allocate_working_buffers (frame_rate());
4166 } else if (p == "ltc-source-port") {
4167 reconnect_ltc_input ();
4168 } else if (p == "ltc-sink-port") {
4169 reconnect_ltc_output ();
4170 } else if (p == "timecode-generator-offset") {
4171 ltc_tx_parse_offset();
4172 } else if (p == "auto-return-target-list") {
4173 follow_playhead_priority ();
4180 Session::set_history_depth (uint32_t d)
4182 _history.set_depth (d);
4186 Session::load_diskstreams_2X (XMLNode const & node, int)
4189 XMLNodeConstIterator citer;
4191 clist = node.children();
4193 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4196 /* diskstreams added automatically by DiskstreamCreated handler */
4197 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4198 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4199 _diskstreams_2X.push_back (dsp);
4201 error << _("Session: unknown diskstream type in XML") << endmsg;
4205 catch (failed_constructor& err) {
4206 error << _("Session: could not load diskstream via XML state") << endmsg;
4214 /** Connect things to the MMC object */
4216 Session::setup_midi_machine_control ()
4218 _mmc = new MIDI::MachineControl;
4220 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4221 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4223 if (!async_out || !async_out) {
4227 /* XXXX argh, passing raw pointers back into libmidi++ */
4229 MIDI::Port* mmc_in = async_in.get();
4230 MIDI::Port* mmc_out = async_out.get();
4232 _mmc->set_ports (mmc_in, mmc_out);
4234 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4235 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4236 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4237 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4238 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4239 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4240 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4241 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4242 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4243 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4244 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4245 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4246 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4248 /* also handle MIDI SPP because its so common */
4250 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4251 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4252 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4255 boost::shared_ptr<Controllable>
4256 Session::solo_cut_control() const
4258 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4259 * controls in Ardour that currently get presented to the user in the GUI that require
4260 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4262 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4263 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4266 return _solo_cut_control;
4270 Session::save_snapshot_name (const std::string & n)
4272 /* assure Stateful::_instant_xml is loaded
4273 * add_instant_xml() only adds to existing data and defaults
4274 * to use an empty Tree otherwise
4276 instant_xml ("LastUsedSnapshot");
4278 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4279 last_used_snapshot->set_property ("name", n);
4280 add_instant_xml (*last_used_snapshot, false);
4284 Session::set_snapshot_name (const std::string & n)
4286 _current_snapshot_name = n;
4287 save_snapshot_name (n);
4291 Session::rename (const std::string& new_name)
4293 string legal_name = legalize_for_path (new_name);
4299 string const old_sources_root = _session_dir->sources_root();
4301 if (!_writable || (_state_of_the_state & CannotSave)) {
4302 error << _("Cannot rename read-only session.") << endmsg;
4303 return 0; // don't show "messed up" warning
4305 if (record_status() == Recording) {
4306 error << _("Cannot rename session while recording") << endmsg;
4307 return 0; // don't show "messed up" warning
4310 StateProtector stp (this);
4315 * interchange subdirectory
4319 * Backup files are left unchanged and not renamed.
4322 /* Windows requires that we close all files before attempting the
4323 * rename. This works on other platforms, but isn't necessary there.
4324 * Leave it in place for all platforms though, since it may help
4325 * catch issues that could arise if the way Source files work ever
4326 * change (since most developers are not using Windows).
4329 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4330 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4336 /* pass one: not 100% safe check that the new directory names don't
4340 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4344 /* this is a stupid hack because Glib::path_get_dirname() is
4345 * lexical-only, and so passing it /a/b/c/ gives a different
4346 * result than passing it /a/b/c ...
4349 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4350 oldstr = oldstr.substr (0, oldstr.length() - 1);
4353 string base = Glib::path_get_dirname (oldstr);
4355 newstr = Glib::build_filename (base, legal_name);
4357 cerr << "Looking for " << newstr << endl;
4359 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4360 cerr << " exists\n";
4369 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4375 /* this is a stupid hack because Glib::path_get_dirname() is
4376 * lexical-only, and so passing it /a/b/c/ gives a different
4377 * result than passing it /a/b/c ...
4380 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4381 oldstr = oldstr.substr (0, oldstr.length() - 1);
4384 string base = Glib::path_get_dirname (oldstr);
4385 newstr = Glib::build_filename (base, legal_name);
4387 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4389 cerr << "Rename " << oldstr << " => " << newstr << endl;
4390 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4391 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4392 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4396 /* Reset path in "session dirs" */
4401 /* reset primary SessionDirectory object */
4404 (*_session_dir) = newstr;
4409 /* now rename directory below session_dir/interchange */
4411 string old_interchange_dir;
4412 string new_interchange_dir;
4414 /* use newstr here because we renamed the path
4415 * (folder/directory) that used to be oldstr to newstr above
4418 v.push_back (newstr);
4419 v.push_back (interchange_dir_name);
4420 v.push_back (Glib::path_get_basename (oldstr));
4422 old_interchange_dir = Glib::build_filename (v);
4425 v.push_back (newstr);
4426 v.push_back (interchange_dir_name);
4427 v.push_back (legal_name);
4429 new_interchange_dir = Glib::build_filename (v);
4431 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4433 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4434 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4435 old_interchange_dir, new_interchange_dir,
4438 error << string_compose (_("renaming %s as %2 failed (%3)"),
4439 old_interchange_dir, new_interchange_dir,
4448 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4449 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4451 cerr << "Rename " << oldstr << " => " << newstr << endl;
4453 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4454 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4455 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4461 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4463 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4464 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4466 cerr << "Rename " << oldstr << " => " << newstr << endl;
4468 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4469 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4470 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4475 /* remove old name from recent sessions */
4476 remove_recent_sessions (_path);
4479 /* update file source paths */
4481 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4482 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4484 string p = fs->path ();
4485 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4487 SourceFactory::setup_peakfile(i->second, true);
4491 set_snapshot_name (new_name);
4496 /* save state again to get everything just right */
4498 save_state (_current_snapshot_name);
4500 /* add to recent sessions */
4502 store_recent_sessions (new_name, _path);
4508 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4510 bool found_sr = false;
4511 bool found_data_format = false;
4512 program_version = "";
4514 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4518 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4522 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4525 xmlFreeParserCtxt(ctxt);
4529 xmlNodePtr node = xmlDocGetRootElement(doc);
4532 xmlFreeParserCtxt(ctxt);
4540 for (attr = node->properties; attr; attr = attr->next) {
4541 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4542 sample_rate = atoi ((char*)attr->children->content);
4547 node = node->children;
4548 while (node != NULL) {
4549 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4550 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4552 program_version = string ((const char*)val);
4553 size_t sep = program_version.find_first_of("-");
4554 if (sep != string::npos) {
4555 program_version = program_version.substr (0, sep);
4560 if (strcmp((const char*) node->name, "Config")) {
4564 for (node = node->children; node; node = node->next) {
4565 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4566 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4568 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4570 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4572 found_data_format = true;
4582 xmlFreeParserCtxt(ctxt);
4585 return !(found_sr && found_data_format); // zero if they are both found
4589 Session::get_snapshot_from_instant (const std::string& session_dir)
4591 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4593 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4598 if (!tree.read (instant_xml_path)) {
4602 XMLProperty const * prop;
4603 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4604 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4605 return prop->value();
4611 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4612 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4615 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4619 SourcePathMap source_path_map;
4621 boost::shared_ptr<AudioFileSource> afs;
4626 Glib::Threads::Mutex::Lock lm (source_lock);
4628 cerr << " total sources = " << sources.size();
4630 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4631 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4637 if (fs->within_session()) {
4641 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4642 source_path_map[fs->path()].push_back (fs);
4644 SeveralFileSources v;
4646 source_path_map.insert (make_pair (fs->path(), v));
4652 cerr << " fsources = " << total << endl;
4654 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4656 /* tell caller where we are */
4658 string old_path = i->first;
4660 callback (n, total, old_path);
4662 cerr << old_path << endl;
4666 switch (i->second.front()->type()) {
4667 case DataType::AUDIO:
4668 new_path = new_audio_source_path_for_embedded (old_path);
4671 case DataType::MIDI:
4672 /* XXX not implemented yet */
4676 if (new_path.empty()) {
4680 cerr << "Move " << old_path << " => " << new_path << endl;
4682 if (!copy_file (old_path, new_path)) {
4683 cerr << "failed !\n";
4687 /* make sure we stop looking in the external
4688 dir/folder. Remember, this is an all-or-nothing
4689 operations, it doesn't merge just some files.
4691 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4693 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4694 (*f)->set_path (new_path);
4699 save_state ("", false, false);
4705 bool accept_all_files (string const &, void *)
4711 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4713 /* 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.
4718 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4720 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4722 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4724 v.push_back (new_session_folder); /* full path */
4725 v.push_back (interchange_dir_name);
4726 v.push_back (new_session_path); /* just one directory/folder */
4727 v.push_back (typedir);
4728 v.push_back (Glib::path_get_basename (old_path));
4730 return Glib::build_filename (v);
4734 Session::save_as (SaveAs& saveas)
4736 vector<string> files;
4737 string current_folder = Glib::path_get_dirname (_path);
4738 string new_folder = legalize_for_path (saveas.new_name);
4739 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4740 int64_t total_bytes = 0;
4744 int32_t internal_file_cnt = 0;
4746 vector<string> do_not_copy_extensions;
4747 do_not_copy_extensions.push_back (statefile_suffix);
4748 do_not_copy_extensions.push_back (pending_suffix);
4749 do_not_copy_extensions.push_back (backup_suffix);
4750 do_not_copy_extensions.push_back (temp_suffix);
4751 do_not_copy_extensions.push_back (history_suffix);
4753 /* get total size */
4755 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4757 /* need to clear this because
4758 * find_files_matching_filter() is cumulative
4763 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4765 all += files.size();
4767 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4769 g_stat ((*i).c_str(), &gsb);
4770 total_bytes += gsb.st_size;
4774 /* save old values so we can switch back if we are not switching to the new session */
4776 string old_path = _path;
4777 string old_name = _name;
4778 string old_snapshot = _current_snapshot_name;
4779 string old_sd = _session_dir->root_path();
4780 vector<string> old_search_path[DataType::num_types];
4781 string old_config_search_path[DataType::num_types];
4783 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4784 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4785 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4786 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4788 /* switch session directory */
4790 (*_session_dir) = to_dir;
4792 /* create new tree */
4794 if (!_session_dir->create()) {
4795 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4800 /* copy all relevant files. Find each location in session_dirs,
4801 * and copy files from there to target.
4804 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4806 /* need to clear this because
4807 * find_files_matching_filter() is cumulative
4812 const size_t prefix_len = (*sd).path.size();
4814 /* Work just on the files within this session dir */
4816 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4818 /* add dir separator to protect against collisions with
4819 * track names (e.g. track named "audiofiles" or
4823 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4824 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4825 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4827 /* copy all the files. Handling is different for media files
4828 than others because of the *silly* subtree we have below the interchange
4829 folder. That really was a bad idea, but I'm not fixing it as part of
4830 implementing ::save_as().
4833 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4835 std::string from = *i;
4838 string filename = Glib::path_get_basename (from);
4839 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4840 if (filename == ".DS_STORE") {
4845 if (from.find (audiofile_dir_string) != string::npos) {
4847 /* audio file: only copy if asked */
4849 if (saveas.include_media && saveas.copy_media) {
4851 string to = make_new_media_path (*i, to_dir, new_folder);
4853 info << "media file copying from " << from << " to " << to << endmsg;
4855 if (!copy_file (from, to)) {
4856 throw Glib::FileError (Glib::FileError::IO_ERROR,
4857 string_compose(_("\ncopying \"%1\" failed !"), from));
4861 /* we found media files inside the session folder */
4863 internal_file_cnt++;
4865 } else if (from.find (midifile_dir_string) != string::npos) {
4867 /* midi file: always copy unless
4868 * creating an empty new session
4871 if (saveas.include_media) {
4873 string to = make_new_media_path (*i, to_dir, new_folder);
4875 info << "media file copying from " << from << " to " << to << endmsg;
4877 if (!copy_file (from, to)) {
4878 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4882 /* we found media files inside the session folder */
4884 internal_file_cnt++;
4886 } else if (from.find (analysis_dir_string) != string::npos) {
4888 /* make sure analysis dir exists in
4889 * new session folder, but we're not
4890 * copying analysis files here, see
4894 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4899 /* normal non-media file. Don't copy state, history, etc.
4902 bool do_copy = true;
4904 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4905 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4906 /* end of filename matches extension, do not copy file */
4912 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4913 /* don't copy peakfiles if
4914 * we're not copying media
4920 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4922 info << "attempting to make directory/folder " << to << endmsg;
4924 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4925 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4928 info << "attempting to copy " << from << " to " << to << endmsg;
4930 if (!copy_file (from, to)) {
4931 throw Glib::FileError (Glib::FileError::IO_ERROR,
4932 string_compose(_("\ncopying \"%1\" failed !"), from));
4937 /* measure file size even if we're not going to copy so that our Progress
4938 signals are correct, since we included these do-not-copy files
4939 in the computation of the total size and file count.
4943 g_stat (from.c_str(), &gsb);
4944 copied += gsb.st_size;
4947 double fraction = (double) copied / total_bytes;
4949 bool keep_going = true;
4951 if (saveas.copy_media) {
4953 /* no need or expectation of this if
4954 * media is not being copied, because
4955 * it will be fast(ish).
4958 /* tell someone "X percent, file M of N"; M is one-based */
4960 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4968 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4974 /* copy optional folders, if any */
4976 string old = plugins_dir ();
4977 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4978 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4979 copy_files (old, newdir);
4982 old = externals_dir ();
4983 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4984 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4985 copy_files (old, newdir);
4988 old = automation_dir ();
4989 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4990 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4991 copy_files (old, newdir);
4994 if (saveas.include_media) {
4996 if (saveas.copy_media) {
4997 #ifndef PLATFORM_WINDOWS
4998 /* There are problems with analysis files on
4999 * Windows, because they used a colon in their
5000 * names as late as 4.0. Colons are not legal
5001 * under Windows even if NTFS allows them.
5003 * This is a tricky problem to solve so for
5004 * just don't copy these files. They will be
5005 * regenerated as-needed anyway, subject to the
5006 * existing issue that the filenames will be
5007 * rejected by Windows, which is a separate
5008 * problem (though related).
5011 /* only needed if we are copying media, since the
5012 * analysis data refers to media data
5015 old = analysis_dir ();
5016 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5017 string newdir = Glib::build_filename (to_dir, "analysis");
5018 copy_files (old, newdir);
5020 #endif /* PLATFORM_WINDOWS */
5025 set_snapshot_name (saveas.new_name);
5026 _name = saveas.new_name;
5028 if (saveas.include_media && !saveas.copy_media) {
5030 /* reset search paths of the new session (which we're pretending to be right now) to
5031 include the original session search path, so we can still find all audio.
5034 if (internal_file_cnt) {
5035 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5036 ensure_search_path_includes (*s, DataType::AUDIO);
5037 cerr << "be sure to include " << *s << " for audio" << endl;
5040 /* we do not do this for MIDI because we copy
5041 all MIDI files if saveas.include_media is
5047 bool was_dirty = dirty ();
5049 save_default_options ();
5051 if (saveas.copy_media && saveas.copy_external) {
5052 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5053 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5057 saveas.final_session_folder_name = _path;
5059 store_recent_sessions (_name, _path);
5061 if (!saveas.switch_to) {
5063 /* save the new state */
5065 save_state ("", false, false, !saveas.include_media);
5067 /* switch back to the way things were */
5071 set_snapshot_name (old_snapshot);
5073 (*_session_dir) = old_sd;
5079 if (internal_file_cnt) {
5080 /* reset these to their original values */
5081 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5082 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5087 /* prune session dirs, and update disk space statistics
5092 session_dirs.clear ();
5093 session_dirs.push_back (sp);
5094 refresh_disk_space ();
5096 _writable = exists_and_writable (_path);
5098 /* ensure that all existing tracks reset their current capture source paths
5100 reset_write_sources (true, true);
5102 /* creating new write sources marks the session as
5103 dirty. If the new session is empty, then
5104 save_state() thinks we're saving a template and will
5105 not mark the session as clean. So do that here,
5106 before we save state.
5109 if (!saveas.include_media) {
5110 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5113 save_state ("", false, false, !saveas.include_media);
5115 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5116 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5119 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5120 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5126 if (fs->within_session()) {
5127 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5128 fs->set_path (newpath);
5133 } catch (Glib::FileError& e) {
5135 saveas.failure_message = e.what();
5137 /* recursively remove all the directories */
5139 remove_directory (to_dir);
5147 saveas.failure_message = _("unknown reason");
5149 /* recursively remove all the directories */
5151 remove_directory (to_dir);
5161 static void set_progress (Progress* p, size_t n, size_t t)
5163 p->set_progress (float (n) / float(t));
5167 Session::archive_session (const std::string& dest,
5168 const std::string& name,
5169 ArchiveEncode compress_audio,
5170 bool only_used_sources,
5173 if (dest.empty () || name.empty ()) {
5177 /* save current values */
5178 bool was_dirty = dirty ();
5179 string old_path = _path;
5180 string old_name = _name;
5181 string old_snapshot = _current_snapshot_name;
5182 string old_sd = _session_dir->root_path();
5183 string old_config_search_path[DataType::num_types];
5184 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5185 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5187 /* ensure that session-path is included in search-path */
5189 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5190 if ((*sd).path == old_path) {
5198 /* create temporary dir to save session to */
5199 #ifdef PLATFORM_WINDOWS
5200 char tmp[256] = "C:\\TEMP\\";
5201 GetTempPath (sizeof (tmp), tmp);
5203 char const* tmp = getenv("TMPDIR");
5208 if ((strlen (tmp) + 21) > 1024) {
5213 strcpy (tmptpl, tmp);
5214 strcat (tmptpl, "ardourarchive-XXXXXX");
5215 char* tmpdir = g_mkdtemp (tmptpl);
5221 std::string to_dir = std::string (tmpdir);
5223 /* switch session directory temporarily */
5224 (*_session_dir) = to_dir;
5226 if (!_session_dir->create()) {
5227 (*_session_dir) = old_sd;
5228 remove_directory (to_dir);
5232 /* prepare archive */
5233 string archive = Glib::build_filename (dest, name + ".tar.xz");
5235 PBD::ScopedConnectionList progress_connection;
5236 PBD::FileArchive ar (archive);
5238 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5241 /* collect files to archive */
5242 std::map<string,string> filemap;
5244 vector<string> do_not_copy_extensions;
5245 do_not_copy_extensions.push_back (statefile_suffix);
5246 do_not_copy_extensions.push_back (pending_suffix);
5247 do_not_copy_extensions.push_back (backup_suffix);
5248 do_not_copy_extensions.push_back (temp_suffix);
5249 do_not_copy_extensions.push_back (history_suffix);
5251 vector<string> blacklist_dirs;
5252 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5253 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5254 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5255 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5256 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5257 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5259 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5260 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5262 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5263 if (only_used_sources) {
5264 playlists->sync_all_regions_with_regions ();
5265 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5268 // collect audio sources for this session, calc total size for encoding
5269 // add option to only include *used* sources (see Session::cleanup_sources)
5270 size_t total_size = 0;
5272 Glib::Threads::Mutex::Lock lm (source_lock);
5273 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5274 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5275 if (!afs || afs->readable_length () == 0) {
5279 if (only_used_sources) {
5283 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5288 std::string from = afs->path();
5290 if (compress_audio != NO_ENCODE) {
5291 total_size += afs->readable_length ();
5293 if (afs->within_session()) {
5294 filemap[from] = make_new_media_path (from, name, name);
5296 filemap[from] = make_new_media_path (from, name, name);
5297 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5304 if (compress_audio != NO_ENCODE) {
5306 progress->set_progress (2); // set to "encoding"
5307 progress->set_progress (0);
5310 Glib::Threads::Mutex::Lock lm (source_lock);
5311 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5312 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5313 if (!afs || afs->readable_length () == 0) {
5317 if (only_used_sources) {
5321 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5326 orig_sources[afs] = afs->path();
5327 orig_gain[afs] = afs->gain();
5329 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5330 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5331 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5334 progress->descend ((float)afs->readable_length () / total_size);
5338 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5339 afs->replace_file (new_path);
5340 afs->set_gain (ns->gain(), true);
5343 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5347 progress->ascend ();
5353 progress->set_progress (-1); // set to "archiving"
5354 progress->set_progress (0);
5357 /* index files relevant for this session */
5358 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5359 vector<string> files;
5361 size_t prefix_len = (*sd).path.size();
5362 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5366 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5368 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5369 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5370 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5372 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5373 std::string from = *i;
5376 string filename = Glib::path_get_basename (from);
5377 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5378 if (filename == ".DS_STORE") {
5383 if (from.find (audiofile_dir_string) != string::npos) {
5385 } else if (from.find (midifile_dir_string) != string::npos) {
5386 filemap[from] = make_new_media_path (from, name, name);
5387 } else if (from.find (videofile_dir_string) != string::npos) {
5388 filemap[from] = make_new_media_path (from, name, name);
5390 bool do_copy = true;
5391 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5392 if (from.find (*v) != string::npos) {
5397 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5398 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5405 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5411 /* write session file */
5413 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5415 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5418 save_default_options ();
5420 size_t prefix_len = _path.size();
5421 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5425 /* collect session-state files */
5426 vector<string> files;
5427 do_not_copy_extensions.clear ();
5428 do_not_copy_extensions.push_back (history_suffix);
5430 blacklist_dirs.clear ();
5431 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5433 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5434 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5435 std::string from = *i;
5436 bool do_copy = true;
5437 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5438 if (from.find (*v) != string::npos) {
5443 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5444 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5450 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5454 /* restore original values */
5457 set_snapshot_name (old_snapshot);
5458 (*_session_dir) = old_sd;
5462 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5463 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5465 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5466 i->first->replace_file (i->second);
5468 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5469 i->first->set_gain (i->second, true);
5472 int rv = ar.create (filemap);
5473 remove_directory (to_dir);
5479 Session::undo (uint32_t n)
5481 if (actively_recording()) {
5489 Session::redo (uint32_t n)
5491 if (actively_recording()) {