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 */
662 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
664 // Waves Tracks: always create master bus for Tracks
665 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
666 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
674 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
675 r->input()->ensure_io (count, false, this);
676 r->output()->ensure_io (count, false, this);
682 /* prohibit auto-connect to master, because there isn't one */
683 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
687 add_routes (rl, false, false, false, PresentationInfo::max_order);
690 // Waves Tracks: Skip this. Always use autoconnection for Tracks
691 if (!ARDOUR::Profile->get_trx()) {
693 /* this allows the user to override settings with an environment variable.
696 if (no_auto_connect()) {
697 bus_profile->input_ac = AutoConnectOption (0);
698 bus_profile->output_ac = AutoConnectOption (0);
701 Config->set_input_auto_connect (bus_profile->input_ac);
702 Config->set_output_auto_connect (bus_profile->output_ac);
706 if (Config->get_use_monitor_bus() && bus_profile) {
707 add_monitor_section ();
714 Session::maybe_write_autosave()
716 if (dirty() && record_status() != Recording) {
717 save_state("", true);
722 Session::remove_pending_capture_state ()
724 std::string pending_state_file_path(_session_dir->root_path());
726 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
728 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
730 if (g_remove (pending_state_file_path.c_str()) != 0) {
731 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
732 pending_state_file_path, g_strerror (errno)) << endmsg;
736 /** Rename a state file.
737 * @param old_name Old snapshot name.
738 * @param new_name New snapshot name.
741 Session::rename_state (string old_name, string new_name)
743 if (old_name == _current_snapshot_name || old_name == _name) {
744 /* refuse to rename the current snapshot or the "main" one */
748 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
749 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
751 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
752 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
754 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
755 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
756 old_name, new_name, g_strerror(errno)) << endmsg;
760 /** Remove a state file.
761 * @param snapshot_name Snapshot name.
764 Session::remove_state (string snapshot_name)
766 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
767 // refuse to remove the current snapshot or the "main" one
771 std::string xml_path(_session_dir->root_path());
773 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
775 if (!create_backup_file (xml_path)) {
776 // don't remove it if a backup can't be made
777 // create_backup_file will log the error.
782 if (g_remove (xml_path.c_str()) != 0) {
783 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
784 xml_path, g_strerror (errno)) << endmsg;
788 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
790 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
792 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
795 std::string xml_path(_session_dir->root_path());
797 /* prevent concurrent saves from different threads */
799 Glib::Threads::Mutex::Lock lm (save_state_lock);
801 if (!_writable || (_state_of_the_state & CannotSave)) {
805 if (g_atomic_int_get(&_suspend_save)) {
809 _save_queued = false;
811 snapshot_t fork_state = NormalSave;
812 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) {
813 /* snapshot, close midi */
814 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
818 const int64_t save_start_time = g_get_monotonic_time();
821 /* tell sources we're saving first, in case they write out to a new file
822 * which should be saved with the state rather than the old one */
823 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
825 i->second->session_saved();
826 } catch (Evoral::SMF::FileError& e) {
827 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
831 SessionSaveUnderway (); /* EMIT SIGNAL */
833 bool mark_as_clean = true;
835 if (!snapshot_name.empty() && !switch_to_snapshot) {
836 mark_as_clean = false;
840 mark_as_clean = false;
841 tree.set_root (&get_template());
843 tree.set_root (&state (true, fork_state));
846 if (snapshot_name.empty()) {
847 snapshot_name = _current_snapshot_name;
848 } else if (switch_to_snapshot) {
849 set_snapshot_name (snapshot_name);
852 assert (!snapshot_name.empty());
856 /* proper save: use statefile_suffix (.ardour in English) */
858 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
860 /* make a backup copy of the old file */
862 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
863 // create_backup_file will log the error
869 /* pending save: use pending_suffix (.pending in English) */
870 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
873 std::string tmp_path(_session_dir->root_path());
874 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
876 cerr << "actually writing state to " << tmp_path << endl;
878 if (!tree.write (tmp_path)) {
879 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
880 if (g_remove (tmp_path.c_str()) != 0) {
881 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
882 tmp_path, g_strerror (errno)) << endmsg;
888 cerr << "renaming state to " << xml_path << endl;
890 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
891 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
892 tmp_path, xml_path, g_strerror(errno)) << endmsg;
893 if (g_remove (tmp_path.c_str()) != 0) {
894 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
895 tmp_path, g_strerror (errno)) << endmsg;
903 save_history (snapshot_name);
906 bool was_dirty = dirty();
908 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
911 DirtyChanged (); /* EMIT SIGNAL */
915 StateSaved (snapshot_name); /* EMIT SIGNAL */
919 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
920 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
926 Session::restore_state (string snapshot_name)
928 if (load_state (snapshot_name) == 0) {
929 set_state (*state_tree->root(), Stateful::loading_state_version);
936 Session::load_state (string snapshot_name)
941 state_was_pending = false;
943 /* check for leftover pending state from a crashed capture attempt */
945 std::string xmlpath(_session_dir->root_path());
946 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
948 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
950 /* there is pending state from a crashed capture attempt */
952 boost::optional<int> r = AskAboutPendingState();
953 if (r.get_value_or (1)) {
954 state_was_pending = true;
958 if (!state_was_pending) {
959 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
962 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
963 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
964 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
965 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
970 state_tree = new XMLTree;
974 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
976 if (!state_tree->read (xmlpath)) {
977 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
983 XMLNode const & root (*state_tree->root());
985 if (root.name() != X_("Session")) {
986 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
993 if (root.get_property ("version", version)) {
994 if (version.find ('.') != string::npos) {
995 /* old school version format */
996 if (version[0] == '2') {
997 Stateful::loading_state_version = 2000;
999 Stateful::loading_state_version = 3000;
1002 Stateful::loading_state_version = string_to<int32_t>(version);
1005 /* no version implies very old version of Ardour */
1006 Stateful::loading_state_version = 1000;
1009 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1011 std::string backup_path(_session_dir->root_path());
1012 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1013 backup_path = Glib::build_filename (backup_path, backup_filename);
1015 // only create a backup for a given statefile version once
1017 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1019 VersionMismatch (xmlpath, backup_path);
1021 if (!copy_file (xmlpath, backup_path)) {;
1027 save_snapshot_name (snapshot_name);
1033 Session::load_options (const XMLNode& node)
1035 config.set_variables (node);
1040 Session::save_default_options ()
1042 return config.save_state();
1046 Session::get_state()
1052 Session::get_template()
1054 /* if we don't disable rec-enable, diskstreams
1055 will believe they need to store their capture
1056 sources in their state node.
1059 disable_record (false);
1061 return state(false);
1064 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1065 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1068 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1070 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1073 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1077 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1080 XMLNode* node = new XMLNode("TrackState"); // XXX
1083 PlaylistSet playlists; // SessionPlaylists
1086 // these will work with new_route_from_template()
1087 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1088 child = node->add_child ("Routes");
1089 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1090 if ((*i)->is_auditioner()) {
1093 if ((*i)->is_master() || (*i)->is_monitor()) {
1096 child->add_child_nocopy ((*i)->get_state());
1097 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1099 playlists.insert (track->playlist ());
1103 // on load, Regions in the playlists need to resolve and map Source-IDs
1104 // also playlist needs to be merged or created with new-name..
1105 // ... and Diskstream in tracks adjusted to use the correct playlist
1106 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1107 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1108 child->add_child_nocopy ((*i)->get_state ());
1109 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1110 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1111 const Region::SourceList& sl = (*s)->sources ();
1112 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1113 sources.insert (*sli);
1118 child = node->add_child ("Sources");
1119 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1120 child->add_child_nocopy ((*i)->get_state ());
1121 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1123 #ifdef PLATFORM_WINDOWS
1126 string p = fs->path ();
1127 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1131 std::string sn = Glib::build_filename (path, "share.axml");
1134 tree.set_root (node);
1135 return tree.write (sn.c_str());
1140 struct route_id_compare {
1142 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1144 return r1->id () < r2->id ();
1150 Session::state (bool full_state, snapshot_t snapshot_type)
1153 XMLNode* node = new XMLNode("Session");
1156 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1158 child = node->add_child ("ProgramVersion");
1159 child->set_property("created-with", created_with);
1161 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1162 child->set_property("modified-with", modified_with);
1164 /* store configuration settings */
1168 node->set_property ("name", _name);
1169 node->set_property ("sample-rate", _base_frame_rate);
1171 if (session_dirs.size() > 1) {
1175 vector<space_and_path>::iterator i = session_dirs.begin();
1176 vector<space_and_path>::iterator next;
1178 ++i; /* skip the first one */
1182 while (i != session_dirs.end()) {
1186 if (next != session_dirs.end()) {
1187 p += G_SEARCHPATH_SEPARATOR;
1196 child = node->add_child ("Path");
1197 child->add_content (p);
1199 node->set_property ("end-is-free", _session_range_end_is_free);
1202 /* save the ID counter */
1204 node->set_property ("id-counter", ID::counter());
1206 node->set_property ("name-counter", name_id_counter ());
1208 /* save the event ID counter */
1210 node->set_property ("event-counter", Evoral::event_id_counter());
1212 /* save the VCA counter */
1214 node->set_property ("vca-counter", VCA::get_next_vca_number());
1216 /* various options */
1218 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1219 if (!midi_port_nodes.empty()) {
1220 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1221 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1222 midi_port_stuff->add_child_nocopy (**n);
1224 node->add_child_nocopy (*midi_port_stuff);
1227 XMLNode& cfgxml (config.get_variables ());
1229 /* exclude search-paths from template */
1230 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1231 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1232 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1234 node->add_child_nocopy (cfgxml);
1236 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1238 child = node->add_child ("Sources");
1241 Glib::Threads::Mutex::Lock sl (source_lock);
1243 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1245 /* Don't save information about non-file Sources, or
1246 * about non-destructive file sources that are empty
1247 * and unused by any regions.
1249 boost::shared_ptr<FileSource> fs;
1251 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1255 if (!fs->destructive()) {
1256 if (fs->empty() && !fs->used()) {
1261 if (snapshot_type != NormalSave && fs->within_session ()) {
1262 /* copy MIDI sources to new file
1264 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1265 * because the GUI (midi_region) has a direct pointer to the midi-model
1266 * of the source, as does UndoTransaction.
1268 * On the upside, .mid files are not kept open. The file is only open
1269 * when reading the model initially and when flushing the model to disk:
1270 * source->session_saved () or export.
1272 * We can change the _path of the existing source under the hood, keeping
1273 * all IDs, references and pointers intact.
1275 boost::shared_ptr<SMFSource> ms;
1276 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1277 const std::string ancestor_name = ms->ancestor_name();
1278 const std::string base = PBD::basename_nosuffix(ancestor_name);
1279 const string path = new_midi_source_path (base, false);
1281 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1282 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1283 Source::Lock lm (ms->mutex());
1285 // TODO special-case empty, removable() files: just create a new removable.
1286 // (load + write flushes the model and creates the file)
1288 ms->load_model (lm);
1290 if (ms->write_to (lm, newsrc, Evoral::MinBeats, Evoral::MaxBeats)) {
1291 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1293 if (snapshot_type == SnapshotKeep) {
1294 /* keep working on current session.
1296 * Save snapshot-state with the original filename.
1297 * Switch to use new path for future saves of the main session.
1299 child->add_child_nocopy (ms->get_state());
1303 * ~SMFSource unlinks removable() files.
1305 std::string npath (ms->path ());
1306 ms->replace_file (newsrc->path ());
1307 newsrc->replace_file (npath);
1309 if (snapshot_type == SwitchToSnapshot) {
1310 /* save and switch to snapshot.
1312 * Leave the old file in place (as is).
1313 * Snapshot uses new source directly
1315 child->add_child_nocopy (ms->get_state());
1322 child->add_child_nocopy (siter->second->get_state());
1326 child = node->add_child ("Regions");
1329 Glib::Threads::Mutex::Lock rl (region_lock);
1330 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1331 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1332 boost::shared_ptr<Region> r = i->second;
1333 /* only store regions not attached to playlists */
1334 if (r->playlist() == 0) {
1335 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1336 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1338 child->add_child_nocopy (r->get_state ());
1343 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1345 if (!cassocs.empty()) {
1346 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1348 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1349 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1350 can->set_property (X_("copy"), i->first->id());
1351 can->set_property (X_("original"), i->second->id());
1352 ca->add_child_nocopy (*can);
1359 node->add_child_nocopy (_selection->get_state());
1362 node->add_child_nocopy (_locations->get_state());
1365 Locations loc (*this);
1366 const bool was_dirty = dirty();
1367 // for a template, just create a new Locations, populate it
1368 // with the default start and end, and get the state for that.
1369 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1370 range->set (max_framepos, 0);
1372 XMLNode& locations_state = loc.get_state();
1374 if (ARDOUR::Profile->get_trx() && _locations) {
1375 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1376 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1377 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1378 locations_state.add_child_nocopy ((*i)->get_state ());
1382 node->add_child_nocopy (locations_state);
1384 /* adding a location above will have marked the session
1385 * dirty. This is an artifact, so fix it if the session wasn't
1390 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1394 child = node->add_child ("Bundles");
1396 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1397 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1398 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1400 child->add_child_nocopy (b->get_state());
1405 node->add_child_nocopy (_vca_manager->get_state());
1407 child = node->add_child ("Routes");
1409 boost::shared_ptr<RouteList> r = routes.reader ();
1411 route_id_compare cmp;
1412 RouteList xml_node_order (*r);
1413 xml_node_order.sort (cmp);
1415 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1416 if (!(*i)->is_auditioner()) {
1418 child->add_child_nocopy ((*i)->get_state());
1420 child->add_child_nocopy ((*i)->get_template());
1426 playlists->add_state (node, full_state);
1428 child = node->add_child ("RouteGroups");
1429 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1430 child->add_child_nocopy ((*i)->get_state());
1434 XMLNode* gain_child = node->add_child ("Click");
1435 gain_child->add_child_nocopy (_click_io->state (full_state));
1436 gain_child->add_child_nocopy (_click_gain->state (full_state));
1440 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1441 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1445 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1446 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1449 node->add_child_nocopy (_speakers->get_state());
1450 node->add_child_nocopy (_tempo_map->get_state());
1451 node->add_child_nocopy (get_control_protocol_state());
1454 node->add_child_copy (*_extra_xml);
1458 Glib::Threads::Mutex::Lock lm (lua_lock);
1461 luabridge::LuaRef savedstate ((*_lua_save)());
1462 saved = savedstate.cast<std::string>();
1464 lua.collect_garbage ();
1467 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1468 std::string b64s (b64);
1471 XMLNode* script_node = new XMLNode (X_("Script"));
1472 script_node->set_property (X_("lua"), LUA_VERSION);
1473 script_node->add_content (b64s);
1474 node->add_child_nocopy (*script_node);
1481 Session::get_control_protocol_state ()
1483 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1484 return cpm.get_state();
1488 Session::set_state (const XMLNode& node, int version)
1495 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1497 if (node.name() != X_("Session")) {
1498 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1502 node.get_property ("name", _name);
1504 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1506 _nominal_frame_rate = _base_frame_rate;
1508 assert (AudioEngine::instance()->running ());
1509 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1510 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1511 if (r.get_value_or (0)) {
1517 created_with = "unknown";
1518 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1519 child->get_property (X_("created-with"), created_with);
1522 setup_raid_path(_session_dir->root_path());
1524 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1527 if (node.get_property (X_("id-counter"), counter)) {
1528 ID::init_counter (counter);
1530 /* old sessions used a timebased counter, so fake
1531 * the startup ID counter based on a standard
1536 ID::init_counter (now);
1539 if (node.get_property (X_("name-counter"), counter)) {
1540 init_name_id_counter (counter);
1543 if (node.get_property (X_("event-counter"), counter)) {
1544 Evoral::init_event_id_counter (counter);
1547 if (node.get_property (X_("vca-counter"), counter)) {
1548 VCA::set_next_vca_number (counter);
1550 VCA::set_next_vca_number (1);
1553 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1554 _midi_ports->set_midi_port_states (child->children());
1557 IO::disable_connecting ();
1559 Stateful::save_extra_xml (node);
1561 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1562 load_options (*child);
1563 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1564 load_options (*child);
1566 error << _("Session: XML state has no options section") << endmsg;
1569 if (version >= 3000) {
1570 if ((child = find_named_node (node, "Metadata")) == 0) {
1571 warning << _("Session: XML state has no metadata section") << endmsg;
1572 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1577 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1578 _speakers->set_state (*child, version);
1581 if ((child = find_named_node (node, "Sources")) == 0) {
1582 error << _("Session: XML state has no sources section") << endmsg;
1584 } else if (load_sources (*child)) {
1588 if ((child = find_named_node (node, "TempoMap")) == 0) {
1589 error << _("Session: XML state has no Tempo Map section") << endmsg;
1591 } else if (_tempo_map->set_state (*child, version)) {
1595 if ((child = find_named_node (node, "Locations")) == 0) {
1596 error << _("Session: XML state has no locations section") << endmsg;
1598 } else if (_locations->set_state (*child, version)) {
1602 locations_changed ();
1604 if (_session_range_location) {
1605 AudioFileSource::set_header_position_offset (_session_range_location->start());
1608 if ((child = find_named_node (node, "Regions")) == 0) {
1609 error << _("Session: XML state has no Regions section") << endmsg;
1611 } else if (load_regions (*child)) {
1615 if ((child = find_named_node (node, "Playlists")) == 0) {
1616 error << _("Session: XML state has no playlists section") << endmsg;
1618 } else if (playlists->load (*this, *child)) {
1622 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1624 } else if (playlists->load_unused (*this, *child)) {
1628 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1629 if (load_compounds (*child)) {
1634 if (version >= 3000) {
1635 if ((child = find_named_node (node, "Bundles")) == 0) {
1636 warning << _("Session: XML state has no bundles section") << endmsg;
1639 /* We can't load Bundles yet as they need to be able
1640 * to convert from port names to Port objects, which can't happen until
1642 _bundle_xml_node = new XMLNode (*child);
1646 if (version < 3000) {
1647 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1648 error << _("Session: XML state has no diskstreams section") << endmsg;
1650 } else if (load_diskstreams_2X (*child, version)) {
1655 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1656 _vca_manager->set_state (*child, version);
1659 if ((child = find_named_node (node, "Routes")) == 0) {
1660 error << _("Session: XML state has no routes section") << endmsg;
1662 } else if (load_routes (*child, version)) {
1666 /* Now that we have Routes and masters loaded, connect them if appropriate */
1668 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1670 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1671 _diskstreams_2X.clear ();
1673 if (version >= 3000) {
1675 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1676 error << _("Session: XML state has no route groups section") << endmsg;
1678 } else if (load_route_groups (*child, version)) {
1682 } else if (version < 3000) {
1684 if ((child = find_named_node (node, "EditGroups")) == 0) {
1685 error << _("Session: XML state has no edit groups section") << endmsg;
1687 } else if (load_route_groups (*child, version)) {
1691 if ((child = find_named_node (node, "MixGroups")) == 0) {
1692 error << _("Session: XML state has no mix groups section") << endmsg;
1694 } else if (load_route_groups (*child, version)) {
1699 if ((child = find_named_node (node, "Click")) == 0) {
1700 warning << _("Session: XML state has no click section") << endmsg;
1701 } else if (_click_io) {
1702 setup_click_state (&node);
1705 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1706 ControlProtocolManager::instance().set_state (*child, version);
1709 if ((child = find_named_node (node, "Script"))) {
1710 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1711 if (!(*n)->is_content ()) { continue; }
1713 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1715 Glib::Threads::Mutex::Lock lm (lua_lock);
1716 (*_lua_load)(std::string ((const char*)buf, size));
1717 } catch (luabridge::LuaException const& e) {
1718 cerr << "LuaException:" << e.what () << endl;
1724 if ((child = find_named_node (node, X_("Selection")))) {
1725 _selection->set_state (*child, version);
1728 update_route_record_state ();
1730 /* here beginneth the second phase ... */
1731 set_snapshot_name (_current_snapshot_name);
1733 StateReady (); /* EMIT SIGNAL */
1746 Session::load_routes (const XMLNode& node, int version)
1749 XMLNodeConstIterator niter;
1750 RouteList new_routes;
1752 nlist = node.children();
1756 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1758 boost::shared_ptr<Route> route;
1759 if (version < 3000) {
1760 route = XMLRouteFactory_2X (**niter, version);
1762 route = XMLRouteFactory (**niter, version);
1766 error << _("Session: cannot create Route from XML description.") << endmsg;
1770 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1772 new_routes.push_back (route);
1775 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1777 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1779 BootMessage (_("Finished adding tracks/busses"));
1784 boost::shared_ptr<Route>
1785 Session::XMLRouteFactory (const XMLNode& node, int version)
1787 boost::shared_ptr<Route> ret;
1789 if (node.name() != "Route") {
1793 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1795 DataType type = DataType::AUDIO;
1796 node.get_property("default-type", type);
1798 assert (type != DataType::NIL);
1802 boost::shared_ptr<Track> track;
1804 if (type == DataType::AUDIO) {
1805 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1807 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1810 if (track->init()) {
1814 if (track->set_state (node, version)) {
1818 BOOST_MARK_TRACK (track);
1822 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1823 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1825 if (r->init () == 0 && r->set_state (node, version) == 0) {
1826 BOOST_MARK_ROUTE (r);
1834 boost::shared_ptr<Route>
1835 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1837 boost::shared_ptr<Route> ret;
1839 if (node.name() != "Route") {
1843 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1845 ds_prop = node.property (X_("diskstream"));
1848 DataType type = DataType::AUDIO;
1849 node.get_property("default-type", type);
1851 assert (type != DataType::NIL);
1855 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1856 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1860 if (i == _diskstreams_2X.end()) {
1861 error << _("Could not find diskstream for route") << endmsg;
1862 return boost::shared_ptr<Route> ();
1865 boost::shared_ptr<Track> track;
1867 if (type == DataType::AUDIO) {
1868 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1870 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1873 if (track->init()) {
1877 if (track->set_state (node, version)) {
1881 track->set_diskstream (*i);
1883 BOOST_MARK_TRACK (track);
1887 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1888 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1890 if (r->init () == 0 && r->set_state (node, version) == 0) {
1891 BOOST_MARK_ROUTE (r);
1900 Session::load_regions (const XMLNode& node)
1903 XMLNodeConstIterator niter;
1904 boost::shared_ptr<Region> region;
1906 nlist = node.children();
1910 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1911 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1912 error << _("Session: cannot create Region from XML description.");
1913 XMLProperty const * name = (**niter).property("name");
1916 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1927 Session::load_compounds (const XMLNode& node)
1929 XMLNodeList calist = node.children();
1930 XMLNodeConstIterator caiter;
1931 XMLProperty const * caprop;
1933 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1934 XMLNode* ca = *caiter;
1938 if ((caprop = ca->property (X_("original"))) == 0) {
1941 orig_id = caprop->value();
1943 if ((caprop = ca->property (X_("copy"))) == 0) {
1946 copy_id = caprop->value();
1948 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1949 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1951 if (!orig || !copy) {
1952 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1958 RegionFactory::add_compound_association (orig, copy);
1965 Session::load_nested_sources (const XMLNode& node)
1968 XMLNodeConstIterator niter;
1970 nlist = node.children();
1972 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1973 if ((*niter)->name() == "Source") {
1975 /* it may already exist, so don't recreate it unnecessarily
1978 XMLProperty const * prop = (*niter)->property (X_("id"));
1980 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1984 ID source_id (prop->value());
1986 if (!source_by_id (source_id)) {
1989 SourceFactory::create (*this, **niter, true);
1991 catch (failed_constructor& err) {
1992 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1999 boost::shared_ptr<Region>
2000 Session::XMLRegionFactory (const XMLNode& node, bool full)
2002 XMLProperty const * type = node.property("type");
2006 const XMLNodeList& nlist = node.children();
2008 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2009 XMLNode *child = (*niter);
2010 if (child->name() == "NestedSource") {
2011 load_nested_sources (*child);
2015 if (!type || type->value() == "audio") {
2016 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2017 } else if (type->value() == "midi") {
2018 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2021 } catch (failed_constructor& err) {
2022 return boost::shared_ptr<Region> ();
2025 return boost::shared_ptr<Region> ();
2028 boost::shared_ptr<AudioRegion>
2029 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2031 XMLProperty const * prop;
2032 boost::shared_ptr<Source> source;
2033 boost::shared_ptr<AudioSource> as;
2035 SourceList master_sources;
2036 uint32_t nchans = 1;
2039 if (node.name() != X_("Region")) {
2040 return boost::shared_ptr<AudioRegion>();
2043 node.get_property (X_("channels"), nchans);
2045 if ((prop = node.property ("name")) == 0) {
2046 cerr << "no name for this region\n";
2050 if ((prop = node.property (X_("source-0"))) == 0) {
2051 if ((prop = node.property ("source")) == 0) {
2052 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2053 return boost::shared_ptr<AudioRegion>();
2057 PBD::ID s_id (prop->value());
2059 if ((source = source_by_id (s_id)) == 0) {
2060 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2061 return boost::shared_ptr<AudioRegion>();
2064 as = boost::dynamic_pointer_cast<AudioSource>(source);
2066 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2067 return boost::shared_ptr<AudioRegion>();
2070 sources.push_back (as);
2072 /* pickup other channels */
2074 for (uint32_t n=1; n < nchans; ++n) {
2075 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2076 if ((prop = node.property (buf)) != 0) {
2078 PBD::ID id2 (prop->value());
2080 if ((source = source_by_id (id2)) == 0) {
2081 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2082 return boost::shared_ptr<AudioRegion>();
2085 as = boost::dynamic_pointer_cast<AudioSource>(source);
2087 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2088 return boost::shared_ptr<AudioRegion>();
2090 sources.push_back (as);
2094 for (uint32_t n = 0; n < nchans; ++n) {
2095 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2096 if ((prop = node.property (buf)) != 0) {
2098 PBD::ID id2 (prop->value());
2100 if ((source = source_by_id (id2)) == 0) {
2101 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2102 return boost::shared_ptr<AudioRegion>();
2105 as = boost::dynamic_pointer_cast<AudioSource>(source);
2107 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2108 return boost::shared_ptr<AudioRegion>();
2110 master_sources.push_back (as);
2115 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2117 /* a final detail: this is the one and only place that we know how long missing files are */
2119 if (region->whole_file()) {
2120 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2121 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2123 sfp->set_length (region->length());
2128 if (!master_sources.empty()) {
2129 if (master_sources.size() != nchans) {
2130 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2132 region->set_master_sources (master_sources);
2140 catch (failed_constructor& err) {
2141 return boost::shared_ptr<AudioRegion>();
2145 boost::shared_ptr<MidiRegion>
2146 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2148 XMLProperty const * prop;
2149 boost::shared_ptr<Source> source;
2150 boost::shared_ptr<MidiSource> ms;
2153 if (node.name() != X_("Region")) {
2154 return boost::shared_ptr<MidiRegion>();
2157 if ((prop = node.property ("name")) == 0) {
2158 cerr << "no name for this region\n";
2162 if ((prop = node.property (X_("source-0"))) == 0) {
2163 if ((prop = node.property ("source")) == 0) {
2164 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2165 return boost::shared_ptr<MidiRegion>();
2169 PBD::ID s_id (prop->value());
2171 if ((source = source_by_id (s_id)) == 0) {
2172 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2173 return boost::shared_ptr<MidiRegion>();
2176 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2178 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2179 return boost::shared_ptr<MidiRegion>();
2182 sources.push_back (ms);
2185 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2186 /* a final detail: this is the one and only place that we know how long missing files are */
2188 if (region->whole_file()) {
2189 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2190 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2192 sfp->set_length (region->length());
2200 catch (failed_constructor& err) {
2201 return boost::shared_ptr<MidiRegion>();
2206 Session::get_sources_as_xml ()
2209 XMLNode* node = new XMLNode (X_("Sources"));
2210 Glib::Threads::Mutex::Lock lm (source_lock);
2212 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2213 node->add_child_nocopy (i->second->get_state());
2220 Session::reset_write_sources (bool mark_write_complete, bool force)
2222 boost::shared_ptr<RouteList> rl = routes.reader();
2223 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2224 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2226 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2227 tr->reset_write_sources(mark_write_complete, force);
2228 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2234 Session::load_sources (const XMLNode& node)
2237 XMLNodeConstIterator niter;
2238 /* don't need this but it stops some
2239 * versions of gcc complaining about
2240 * discarded return values.
2242 boost::shared_ptr<Source> source;
2244 nlist = node.children();
2247 std::map<std::string, std::string> relocation;
2249 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2250 #ifdef PLATFORM_WINDOWS
2254 XMLNode srcnode (**niter);
2255 bool try_replace_abspath = true;
2259 #ifdef PLATFORM_WINDOWS
2260 // do not show "insert media" popups (files embedded from removable media).
2261 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2263 if ((source = XMLSourceFactory (srcnode)) == 0) {
2264 error << _("Session: cannot create Source from XML description.") << endmsg;
2266 #ifdef PLATFORM_WINDOWS
2267 SetErrorMode(old_mode);
2270 } catch (MissingSource& err) {
2271 #ifdef PLATFORM_WINDOWS
2272 SetErrorMode(old_mode);
2275 /* try previous abs path replacements first */
2276 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2277 std::string dir = Glib::path_get_dirname (err.path);
2278 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2279 if (rl != relocation.end ()) {
2280 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2281 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2282 srcnode.set_property ("origin", newpath);
2283 try_replace_abspath = false;
2290 _missing_file_replacement = "";
2292 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2293 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2294 PROGRAM_NAME) << endmsg;
2298 if (!no_questions_about_missing_files) {
2299 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2304 switch (user_choice) {
2306 /* user added a new search location
2307 * or selected a new absolute path,
2309 if (Glib::path_is_absolute (err.path)) {
2310 if (!_missing_file_replacement.empty ()) {
2311 /* replace origin, in XML */
2312 std::string newpath = Glib::build_filename (
2313 _missing_file_replacement, Glib::path_get_basename (err.path));
2314 srcnode.set_property ("origin", newpath);
2315 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2316 _missing_file_replacement = "";
2323 /* user asked to quit the entire session load */
2327 no_questions_about_missing_files = true;
2331 no_questions_about_missing_files = true;
2338 case DataType::AUDIO:
2339 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2342 case DataType::MIDI:
2343 /* The MIDI file is actually missing so
2344 * just create a new one in the same
2345 * location. Do not announce its
2349 if (!Glib::path_is_absolute (err.path)) {
2350 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2352 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2357 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2358 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2359 /* reset ID to match the missing one */
2360 source->set_id (**niter);
2361 /* Now we can announce it */
2362 SourceFactory::SourceCreated (source);
2373 boost::shared_ptr<Source>
2374 Session::XMLSourceFactory (const XMLNode& node)
2376 if (node.name() != "Source") {
2377 return boost::shared_ptr<Source>();
2381 /* note: do peak building in another thread when loading session state */
2382 return SourceFactory::create (*this, node, true);
2385 catch (failed_constructor& err) {
2386 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2387 return boost::shared_ptr<Source>();
2392 Session::save_template (string template_name, bool replace_existing)
2394 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2398 bool absolute_path = Glib::path_is_absolute (template_name);
2400 /* directory to put the template in */
2401 std::string template_dir_path;
2403 if (!absolute_path) {
2404 std::string user_template_dir(user_template_directory());
2406 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2407 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2408 user_template_dir, g_strerror (errno)) << endmsg;
2412 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2414 template_dir_path = template_name;
2417 if (!ARDOUR::Profile->get_trx()) {
2418 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2419 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2420 template_dir_path) << endmsg;
2424 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2425 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2426 template_dir_path, g_strerror (errno)) << endmsg;
2432 std::string template_file_path;
2434 if (ARDOUR::Profile->get_trx()) {
2435 template_file_path = template_name;
2437 if (absolute_path) {
2438 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2440 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2444 SessionSaveUnderway (); /* EMIT SIGNAL */
2449 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2450 tree.set_root (&get_template());
2453 if (!tree.write (template_file_path)) {
2454 error << _("template not saved") << endmsg;
2458 store_recent_templates (template_file_path);
2464 Session::refresh_disk_space ()
2466 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2468 Glib::Threads::Mutex::Lock lm (space_lock);
2470 /* get freespace on every FS that is part of the session path */
2472 _total_free_4k_blocks = 0;
2473 _total_free_4k_blocks_uncertain = false;
2475 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2476 #if defined(__NetBSD__)
2477 struct statvfs statfsbuf;
2479 statvfs (i->path.c_str(), &statfsbuf);
2481 struct statfs statfsbuf;
2483 statfs (i->path.c_str(), &statfsbuf);
2485 double const scale = statfsbuf.f_bsize / 4096.0;
2487 /* See if this filesystem is read-only */
2488 struct statvfs statvfsbuf;
2489 statvfs (i->path.c_str(), &statvfsbuf);
2491 /* f_bavail can be 0 if it is undefined for whatever
2492 filesystem we are looking at; Samba shares mounted
2493 via GVFS are an example of this.
2495 if (statfsbuf.f_bavail == 0) {
2496 /* block count unknown */
2498 i->blocks_unknown = true;
2499 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2500 /* read-only filesystem */
2502 i->blocks_unknown = false;
2504 /* read/write filesystem with known space */
2505 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2506 i->blocks_unknown = false;
2509 _total_free_4k_blocks += i->blocks;
2510 if (i->blocks_unknown) {
2511 _total_free_4k_blocks_uncertain = true;
2514 #elif defined PLATFORM_WINDOWS
2515 vector<string> scanned_volumes;
2516 vector<string>::iterator j;
2517 vector<space_and_path>::iterator i;
2518 DWORD nSectorsPerCluster, nBytesPerSector,
2519 nFreeClusters, nTotalClusters;
2523 _total_free_4k_blocks = 0;
2525 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2526 strncpy (disk_drive, (*i).path.c_str(), 3);
2530 volume_found = false;
2531 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2533 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2534 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2535 i->blocks = (uint32_t)(nFreeBytes / 4096);
2537 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2538 if (0 == j->compare(disk_drive)) {
2539 volume_found = true;
2544 if (!volume_found) {
2545 scanned_volumes.push_back(disk_drive);
2546 _total_free_4k_blocks += i->blocks;
2551 if (0 == _total_free_4k_blocks) {
2552 strncpy (disk_drive, path().c_str(), 3);
2555 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2557 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2558 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2559 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2566 Session::get_best_session_directory_for_new_audio ()
2568 vector<space_and_path>::iterator i;
2569 string result = _session_dir->root_path();
2571 /* handle common case without system calls */
2573 if (session_dirs.size() == 1) {
2577 /* OK, here's the algorithm we're following here:
2579 We want to select which directory to use for
2580 the next file source to be created. Ideally,
2581 we'd like to use a round-robin process so as to
2582 get maximum performance benefits from splitting
2583 the files across multiple disks.
2585 However, in situations without much diskspace, an
2586 RR approach may end up filling up a filesystem
2587 with new files while others still have space.
2588 Its therefore important to pay some attention to
2589 the freespace in the filesystem holding each
2590 directory as well. However, if we did that by
2591 itself, we'd keep creating new files in the file
2592 system with the most space until it was as full
2593 as all others, thus negating any performance
2594 benefits of this RAID-1 like approach.
2596 So, we use a user-configurable space threshold. If
2597 there are at least 2 filesystems with more than this
2598 much space available, we use RR selection between them.
2599 If not, then we pick the filesystem with the most space.
2601 This gets a good balance between the two
2605 refresh_disk_space ();
2607 int free_enough = 0;
2609 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2610 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2615 if (free_enough >= 2) {
2616 /* use RR selection process, ensuring that the one
2620 i = last_rr_session_dir;
2623 if (++i == session_dirs.end()) {
2624 i = session_dirs.begin();
2627 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2628 SessionDirectory sdir(i->path);
2629 if (sdir.create ()) {
2631 last_rr_session_dir = i;
2636 } while (i != last_rr_session_dir);
2640 /* pick FS with the most freespace (and that
2641 seems to actually work ...)
2644 vector<space_and_path> sorted;
2645 space_and_path_ascending_cmp cmp;
2647 sorted = session_dirs;
2648 sort (sorted.begin(), sorted.end(), cmp);
2650 for (i = sorted.begin(); i != sorted.end(); ++i) {
2651 SessionDirectory sdir(i->path);
2652 if (sdir.create ()) {
2654 last_rr_session_dir = i;
2664 Session::automation_dir () const
2666 return Glib::build_filename (_path, automation_dir_name);
2670 Session::analysis_dir () const
2672 return Glib::build_filename (_path, analysis_dir_name);
2676 Session::plugins_dir () const
2678 return Glib::build_filename (_path, plugins_dir_name);
2682 Session::externals_dir () const
2684 return Glib::build_filename (_path, externals_dir_name);
2688 Session::load_bundles (XMLNode const & node)
2690 XMLNodeList nlist = node.children();
2691 XMLNodeConstIterator niter;
2695 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2696 if ((*niter)->name() == "InputBundle") {
2697 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2698 } else if ((*niter)->name() == "OutputBundle") {
2699 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2701 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2710 Session::load_route_groups (const XMLNode& node, int version)
2712 XMLNodeList nlist = node.children();
2713 XMLNodeConstIterator niter;
2717 if (version >= 3000) {
2719 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2720 if ((*niter)->name() == "RouteGroup") {
2721 RouteGroup* rg = new RouteGroup (*this, "");
2722 add_route_group (rg);
2723 rg->set_state (**niter, version);
2727 } else if (version < 3000) {
2729 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2730 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2731 RouteGroup* rg = new RouteGroup (*this, "");
2732 add_route_group (rg);
2733 rg->set_state (**niter, version);
2742 state_file_filter (const string &str, void* /*arg*/)
2744 return (str.length() > strlen(statefile_suffix) &&
2745 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2749 remove_end(string state)
2751 string statename(state);
2753 string::size_type start,end;
2754 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2755 statename = statename.substr (start+1);
2758 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2759 end = statename.length();
2762 return string(statename.substr (0, end));
2766 Session::possible_states (string path)
2768 vector<string> states;
2769 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2771 transform(states.begin(), states.end(), states.begin(), remove_end);
2773 sort (states.begin(), states.end());
2779 Session::possible_states () const
2781 return possible_states(_path);
2785 Session::new_route_group (const std::string& name)
2787 RouteGroup* rg = NULL;
2789 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2790 if ((*i)->name () == name) {
2797 rg = new RouteGroup (*this, name);
2798 add_route_group (rg);
2804 Session::add_route_group (RouteGroup* g)
2806 _route_groups.push_back (g);
2807 route_group_added (g); /* EMIT SIGNAL */
2809 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2810 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2811 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2817 Session::remove_route_group (RouteGroup& rg)
2819 list<RouteGroup*>::iterator i;
2821 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2822 _route_groups.erase (i);
2825 route_group_removed (); /* EMIT SIGNAL */
2829 /** Set a new order for our route groups, without adding or removing any.
2830 * @param groups Route group list in the new order.
2833 Session::reorder_route_groups (list<RouteGroup*> groups)
2835 _route_groups = groups;
2837 route_groups_reordered (); /* EMIT SIGNAL */
2843 Session::route_group_by_name (string name)
2845 list<RouteGroup *>::iterator i;
2847 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2848 if ((*i)->name() == name) {
2856 Session::all_route_group() const
2858 return *_all_route_group;
2862 Session::add_commands (vector<Command*> const & cmds)
2864 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2870 Session::add_command (Command* const cmd)
2872 assert (_current_trans);
2873 DEBUG_UNDO_HISTORY (
2874 string_compose ("Current Undo Transaction %1, adding command: %2",
2875 _current_trans->name (),
2877 _current_trans->add_command (cmd);
2880 PBD::StatefulDiffCommand*
2881 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2883 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2889 Session::begin_reversible_command (const string& name)
2891 begin_reversible_command (g_quark_from_string (name.c_str ()));
2894 /** Begin a reversible command using a GQuark to identify it.
2895 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2896 * but there must be as many begin...()s as there are commit...()s.
2899 Session::begin_reversible_command (GQuark q)
2901 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2902 to hold all the commands that are committed. This keeps the order of
2903 commands correct in the history.
2906 if (_current_trans == 0) {
2907 DEBUG_UNDO_HISTORY (string_compose (
2908 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2910 /* start a new transaction */
2911 assert (_current_trans_quarks.empty ());
2912 _current_trans = new UndoTransaction();
2913 _current_trans->set_name (g_quark_to_string (q));
2915 DEBUG_UNDO_HISTORY (
2916 string_compose ("Begin Reversible Command, current transaction: %1",
2917 _current_trans->name ()));
2920 _current_trans_quarks.push_front (q);
2924 Session::abort_reversible_command ()
2926 if (_current_trans != 0) {
2927 DEBUG_UNDO_HISTORY (
2928 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2929 _current_trans->clear();
2930 delete _current_trans;
2932 _current_trans_quarks.clear();
2937 Session::commit_reversible_command (Command *cmd)
2939 assert (_current_trans);
2940 assert (!_current_trans_quarks.empty ());
2945 DEBUG_UNDO_HISTORY (
2946 string_compose ("Current Undo Transaction %1, adding command: %2",
2947 _current_trans->name (),
2949 _current_trans->add_command (cmd);
2952 DEBUG_UNDO_HISTORY (
2953 string_compose ("Commit Reversible Command, current transaction: %1",
2954 _current_trans->name ()));
2956 _current_trans_quarks.pop_front ();
2958 if (!_current_trans_quarks.empty ()) {
2959 DEBUG_UNDO_HISTORY (
2960 string_compose ("Commit Reversible Command, transaction is not "
2961 "top-level, current transaction: %1",
2962 _current_trans->name ()));
2963 /* the transaction we're committing is not the top-level one */
2967 if (_current_trans->empty()) {
2968 /* no commands were added to the transaction, so just get rid of it */
2969 DEBUG_UNDO_HISTORY (
2970 string_compose ("Commit Reversible Command, No commands were "
2971 "added to current transaction: %1",
2972 _current_trans->name ()));
2973 delete _current_trans;
2978 gettimeofday (&now, 0);
2979 _current_trans->set_timestamp (now);
2981 _history.add (_current_trans);
2986 accept_all_audio_files (const string& path, void* /*arg*/)
2988 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2992 if (!AudioFileSource::safe_audio_file_extension (path)) {
3000 accept_all_midi_files (const string& path, void* /*arg*/)
3002 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3006 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3007 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3008 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3012 accept_all_state_files (const string& path, void* /*arg*/)
3014 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3018 std::string const statefile_ext (statefile_suffix);
3019 if (path.length() >= statefile_ext.length()) {
3020 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3027 Session::find_all_sources (string path, set<string>& result)
3032 if (!tree.read (path)) {
3036 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3041 XMLNodeConstIterator niter;
3043 nlist = node->children();
3047 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3049 XMLProperty const * prop;
3051 if ((prop = (*niter)->property (X_("type"))) == 0) {
3055 DataType type (prop->value());
3057 if ((prop = (*niter)->property (X_("name"))) == 0) {
3061 if (Glib::path_is_absolute (prop->value())) {
3062 /* external file, ignore */
3070 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3071 result.insert (found_path);
3079 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3081 vector<string> state_files;
3083 string this_snapshot_path;
3089 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3090 ripped = ripped.substr (0, ripped.length() - 1);
3093 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3095 if (state_files.empty()) {
3100 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3101 this_snapshot_path += statefile_suffix;
3103 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3105 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3107 if (exclude_this_snapshot && *i == this_snapshot_path) {
3108 cerr << "\texcluded\n";
3113 if (find_all_sources (*i, result) < 0) {
3121 struct RegionCounter {
3122 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3123 AudioSourceList::iterator iter;
3124 boost::shared_ptr<Region> region;
3127 RegionCounter() : count (0) {}
3131 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3133 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3134 return r.get_value_or (1);
3138 Session::cleanup_regions ()
3140 bool removed = false;
3141 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3143 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3145 uint32_t used = playlists->region_use_count (i->second);
3147 if (used == 0 && !i->second->automatic ()) {
3148 boost::weak_ptr<Region> w = i->second;
3151 RegionFactory::map_remove (w);
3158 // re-check to remove parent references of compound regions
3159 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3160 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3164 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3165 if (0 == playlists->region_use_count (i->second)) {
3166 boost::weak_ptr<Region> w = i->second;
3168 RegionFactory::map_remove (w);
3175 /* dump the history list */
3182 Session::can_cleanup_peakfiles () const
3184 if (deletion_in_progress()) {
3187 if (!_writable || (_state_of_the_state & CannotSave)) {
3188 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3191 if (record_status() == Recording) {
3192 error << _("Cannot cleanup peak-files while recording") << endmsg;
3199 Session::cleanup_peakfiles ()
3201 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3206 assert (can_cleanup_peakfiles ());
3207 assert (!peaks_cleanup_in_progres());
3209 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3211 int timeout = 5000; // 5 seconds
3212 while (!SourceFactory::files_with_peaks.empty()) {
3213 Glib::usleep (1000);
3214 if (--timeout < 0) {
3215 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3216 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3221 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3222 boost::shared_ptr<AudioSource> as;
3223 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3224 as->close_peakfile();
3228 PBD::clear_directory (session_directory().peak_path());
3230 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3232 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3233 boost::shared_ptr<AudioSource> as;
3234 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3235 SourceFactory::setup_peakfile(as, true);
3242 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3244 pl->deep_sources (*all_sources);
3248 Session::cleanup_sources (CleanupReport& rep)
3250 // FIXME: needs adaptation to midi
3252 vector<boost::shared_ptr<Source> > dead_sources;
3255 vector<string> candidates;
3256 vector<string> unused;
3257 set<string> sources_used_by_all_snapshots;
3264 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3266 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3268 /* this is mostly for windows which doesn't allow file
3269 * renaming if the file is in use. But we don't special
3270 * case it because we need to know if this causes
3271 * problems, and the easiest way to notice that is to
3272 * keep it in place for all platforms.
3275 request_stop (false);
3277 _butler->wait_until_finished ();
3279 /* consider deleting all unused playlists */
3281 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3286 /* sync the "all regions" property of each playlist with its current state */
3288 playlists->sync_all_regions_with_regions ();
3290 /* find all un-used sources */
3295 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3297 SourceMap::iterator tmp;
3302 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3306 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3307 dead_sources.push_back (i->second);
3308 i->second->drop_references ();
3314 /* build a list of all the possible audio directories for the session */
3316 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3317 SessionDirectory sdir ((*i).path);
3318 asp += sdir.sound_path();
3320 audio_path += asp.to_string();
3323 /* build a list of all the possible midi directories for the session */
3325 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3326 SessionDirectory sdir ((*i).path);
3327 msp += sdir.midi_path();
3329 midi_path += msp.to_string();
3331 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3332 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3334 /* add sources from all other snapshots as "used", but don't use this
3335 snapshot because the state file on disk still references sources we
3336 may have already dropped.
3339 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3341 /* Although the region factory has a list of all regions ever created
3342 * for this session, we're only interested in regions actually in
3343 * playlists right now. So merge all playlist regions lists together.
3345 * This will include the playlists used within compound regions.
3348 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3350 /* add our current source list
3353 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3354 boost::shared_ptr<FileSource> fs;
3355 SourceMap::iterator tmp = i;
3358 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3364 /* this is mostly for windows which doesn't allow file
3365 * renaming if the file is in use. But we do not special
3366 * case it because we need to know if this causes
3367 * problems, and the easiest way to notice that is to
3368 * keep it in place for all platforms.
3373 if (!fs->is_stub()) {
3375 /* Note that we're checking a list of all
3376 * sources across all snapshots with the list
3377 * of sources used by this snapshot.
3380 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3381 /* this source is in use by this snapshot */
3382 sources_used_by_all_snapshots.insert (fs->path());
3383 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3385 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3386 /* this source is NOT in use by this snapshot */
3388 /* remove all related regions from RegionFactory master list */
3390 RegionFactory::remove_regions_using_source (i->second);
3392 /* remove from our current source list
3393 * also. We may not remove it from
3394 * disk, because it may be used by
3395 * other snapshots, but it isn't used inside this
3396 * snapshot anymore, so we don't need a
3407 /* now check each candidate source to see if it exists in the list of
3408 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3411 cerr << "Candidates: " << candidates.size() << endl;
3412 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3414 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3419 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3421 tmppath1 = canonical_path (spath);
3422 tmppath2 = canonical_path ((*i));
3424 cerr << "\t => " << tmppath2 << endl;
3426 if (tmppath1 == tmppath2) {
3433 unused.push_back (spath);
3437 cerr << "Actually unused: " << unused.size() << endl;
3439 if (unused.empty()) {
3445 /* now try to move all unused files into the "dead" directory(ies) */
3447 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3452 /* don't move the file across filesystems, just
3453 * stick it in the `dead_dir_name' directory
3454 * on whichever filesystem it was already on.
3457 if ((*x).find ("/sounds/") != string::npos) {
3459 /* old school, go up 1 level */
3461 newpath = Glib::path_get_dirname (*x); // "sounds"
3462 newpath = Glib::path_get_dirname (newpath); // "session-name"
3466 /* new school, go up 4 levels */
3468 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3469 newpath = Glib::path_get_dirname (newpath); // "session-name"
3470 newpath = Glib::path_get_dirname (newpath); // "interchange"
3471 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3474 newpath = Glib::build_filename (newpath, dead_dir_name);
3476 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3477 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3481 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3483 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3485 /* the new path already exists, try versioning */
3487 char buf[PATH_MAX+1];
3491 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3494 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3495 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3499 if (version == 999) {
3500 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3504 newpath = newpath_v;
3509 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3510 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3511 newpath, g_strerror (errno)) << endmsg;
3515 /* see if there an easy to find peakfile for this file, and remove it. */
3517 string base = Glib::path_get_basename (*x);
3518 base += "%A"; /* this is what we add for the channel suffix of all native files,
3519 * or for the first channel of embedded files. it will miss
3520 * some peakfiles for other channels
3522 string peakpath = construct_peak_filepath (base);
3524 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3525 if (::g_unlink (peakpath.c_str ()) != 0) {
3526 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3527 g_strerror (errno)) << endmsg;
3528 /* try to back out */
3529 ::g_rename (newpath.c_str (), _path.c_str ());
3534 rep.paths.push_back (*x);
3535 rep.space += statbuf.st_size;
3538 /* dump the history list */
3542 /* save state so we don't end up a session file
3543 * referring to non-existent sources.
3550 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3556 Session::cleanup_trash_sources (CleanupReport& rep)
3558 // FIXME: needs adaptation for MIDI
3560 vector<space_and_path>::iterator i;
3566 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3568 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3570 clear_directory (dead_dir, &rep.space, &rep.paths);
3577 Session::set_dirty ()
3579 /* return early if there's nothing to do */
3584 /* never mark session dirty during loading */
3585 if (_state_of_the_state & Loading) {
3589 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3590 DirtyChanged(); /* EMIT SIGNAL */
3594 Session::set_clean ()
3596 bool was_dirty = dirty();
3598 _state_of_the_state = Clean;
3601 DirtyChanged(); /* EMIT SIGNAL */
3606 Session::set_deletion_in_progress ()
3608 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3612 Session::clear_deletion_in_progress ()
3614 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3618 Session::add_controllable (boost::shared_ptr<Controllable> c)
3620 /* this adds a controllable to the list managed by the Session.
3621 this is a subset of those managed by the Controllable class
3622 itself, and represents the only ones whose state will be saved
3623 as part of the session.
3626 Glib::Threads::Mutex::Lock lm (controllables_lock);
3627 controllables.insert (c);
3630 struct null_deleter { void operator()(void const *) const {} };
3633 Session::remove_controllable (Controllable* c)
3635 if (_state_of_the_state & Deletion) {
3639 Glib::Threads::Mutex::Lock lm (controllables_lock);
3641 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3643 if (x != controllables.end()) {
3644 controllables.erase (x);
3648 boost::shared_ptr<Controllable>
3649 Session::controllable_by_id (const PBD::ID& id)
3651 Glib::Threads::Mutex::Lock lm (controllables_lock);
3653 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3654 if ((*i)->id() == id) {
3659 return boost::shared_ptr<Controllable>();
3662 boost::shared_ptr<AutomationControl>
3663 Session::automation_control_by_id (const PBD::ID& id)
3665 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3668 boost::shared_ptr<Controllable>
3669 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3671 boost::shared_ptr<Controllable> c;
3672 boost::shared_ptr<Stripable> s;
3673 boost::shared_ptr<Route> r;
3675 switch (desc.top_level_type()) {
3676 case ControllableDescriptor::NamedRoute:
3678 std::string str = desc.top_level_name();
3680 if (str == "Master" || str == "master") {
3682 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3684 } else if (str == "auditioner") {
3687 s = route_by_name (desc.top_level_name());
3693 case ControllableDescriptor::PresentationOrderRoute:
3694 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3697 case ControllableDescriptor::PresentationOrderTrack:
3698 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3701 case ControllableDescriptor::PresentationOrderBus:
3702 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3705 case ControllableDescriptor::PresentationOrderVCA:
3706 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3709 case ControllableDescriptor::SelectionCount:
3710 s = route_by_selected_count (desc.selection_id());
3718 r = boost::dynamic_pointer_cast<Route> (s);
3720 switch (desc.subtype()) {
3721 case ControllableDescriptor::Gain:
3722 c = s->gain_control ();
3725 case ControllableDescriptor::Trim:
3726 c = s->trim_control ();
3729 case ControllableDescriptor::Solo:
3730 c = s->solo_control();
3733 case ControllableDescriptor::Mute:
3734 c = s->mute_control();
3737 case ControllableDescriptor::Recenable:
3738 c = s->rec_enable_control ();
3741 case ControllableDescriptor::PanDirection:
3742 c = s->pan_azimuth_control();
3745 case ControllableDescriptor::PanWidth:
3746 c = s->pan_width_control();
3749 case ControllableDescriptor::PanElevation:
3750 c = s->pan_elevation_control();
3753 case ControllableDescriptor::Balance:
3754 /* XXX simple pan control */
3757 case ControllableDescriptor::PluginParameter:
3759 uint32_t plugin = desc.target (0);
3760 uint32_t parameter_index = desc.target (1);
3762 /* revert to zero based counting */
3768 if (parameter_index > 0) {
3776 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3779 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3780 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3785 case ControllableDescriptor::SendGain: {
3786 uint32_t send = desc.target (0);
3793 c = r->send_level_controllable (send);
3798 /* relax and return a null pointer */
3806 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3809 Stateful::add_instant_xml (node, _path);
3812 if (write_to_config) {
3813 Config->add_instant_xml (node);
3818 Session::instant_xml (const string& node_name)
3820 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3821 if (get_disable_all_loaded_plugins ()) {
3825 return Stateful::instant_xml (node_name, _path);
3829 Session::save_history (string snapshot_name)
3837 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3838 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3842 if (snapshot_name.empty()) {
3843 snapshot_name = _current_snapshot_name;
3846 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3847 const string backup_filename = history_filename + backup_suffix;
3848 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3849 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3851 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3852 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3853 error << _("could not backup old history file, current history not saved") << endmsg;
3858 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3860 if (!tree.write (xml_path))
3862 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3864 if (g_remove (xml_path.c_str()) != 0) {
3865 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3866 xml_path, g_strerror (errno)) << endmsg;
3868 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3869 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3870 backup_path, g_strerror (errno)) << endmsg;
3880 Session::restore_history (string snapshot_name)
3884 if (snapshot_name.empty()) {
3885 snapshot_name = _current_snapshot_name;
3888 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3889 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3891 info << "Loading history from " << xml_path << endmsg;
3893 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3894 info << string_compose (_("%1: no history file \"%2\" for this session."),
3895 _name, xml_path) << endmsg;
3899 if (!tree.read (xml_path)) {
3900 error << string_compose (_("Could not understand session history file \"%1\""),
3901 xml_path) << endmsg;
3908 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3911 UndoTransaction* ut = new UndoTransaction ();
3917 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3918 !t->get_property ("tv-usec", tv_usec)) {
3922 ut->set_name (name);
3926 tv.tv_usec = tv_usec;
3927 ut->set_timestamp(tv);
3929 for (XMLNodeConstIterator child_it = t->children().begin();
3930 child_it != t->children().end(); child_it++)
3932 XMLNode *n = *child_it;
3935 if (n->name() == "MementoCommand" ||
3936 n->name() == "MementoUndoCommand" ||
3937 n->name() == "MementoRedoCommand") {
3939 if ((c = memento_command_factory(n))) {
3943 } else if (n->name() == "NoteDiffCommand") {
3944 PBD::ID id (n->property("midi-source")->value());
3945 boost::shared_ptr<MidiSource> midi_source =
3946 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3948 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3950 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3953 } else if (n->name() == "SysExDiffCommand") {
3955 PBD::ID id (n->property("midi-source")->value());
3956 boost::shared_ptr<MidiSource> midi_source =
3957 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3959 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3961 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3964 } else if (n->name() == "PatchChangeDiffCommand") {
3966 PBD::ID id (n->property("midi-source")->value());
3967 boost::shared_ptr<MidiSource> midi_source =
3968 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3970 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3972 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3975 } else if (n->name() == "StatefulDiffCommand") {
3976 if ((c = stateful_diff_command_factory (n))) {
3977 ut->add_command (c);
3980 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3991 Session::config_changed (std::string p, bool ours)
3997 if (p == "seamless-loop") {
3999 } else if (p == "rf-speed") {
4001 } else if (p == "auto-loop") {
4003 } else if (p == "session-monitoring") {
4005 } else if (p == "auto-input") {
4007 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4008 /* auto-input only makes a difference if we're rolling */
4009 set_track_monitor_input_status (!config.get_auto_input());
4012 } else if (p == "punch-in") {
4016 if ((location = _locations->auto_punch_location()) != 0) {
4018 if (config.get_punch_in ()) {
4019 replace_event (SessionEvent::PunchIn, location->start());
4021 remove_event (location->start(), SessionEvent::PunchIn);
4025 } else if (p == "punch-out") {
4029 if ((location = _locations->auto_punch_location()) != 0) {
4031 if (config.get_punch_out()) {
4032 replace_event (SessionEvent::PunchOut, location->end());
4034 clear_events (SessionEvent::PunchOut);
4038 } else if (p == "edit-mode") {
4040 Glib::Threads::Mutex::Lock lm (playlists->lock);
4042 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4043 (*i)->set_edit_mode (Config->get_edit_mode ());
4046 } else if (p == "use-video-sync") {
4048 waiting_for_sync_offset = config.get_use_video_sync();
4050 } else if (p == "mmc-control") {
4052 //poke_midi_thread ();
4054 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4056 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4058 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4060 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4062 } else if (p == "midi-control") {
4064 //poke_midi_thread ();
4066 } else if (p == "raid-path") {
4068 setup_raid_path (config.get_raid_path());
4070 } else if (p == "timecode-format") {
4074 } else if (p == "video-pullup") {
4078 } else if (p == "seamless-loop") {
4080 if (play_loop && transport_rolling()) {
4081 // to reset diskstreams etc
4082 request_play_loop (true);
4085 } else if (p == "rf-speed") {
4087 cumulative_rf_motion = 0;
4090 } else if (p == "click-sound") {
4092 setup_click_sounds (1);
4094 } else if (p == "click-emphasis-sound") {
4096 setup_click_sounds (-1);
4098 } else if (p == "clicking") {
4100 if (Config->get_clicking()) {
4101 if (_click_io && click_data) { // don't require emphasis data
4108 } else if (p == "click-record-only") {
4110 _click_rec_only = Config->get_click_record_only();
4112 } else if (p == "click-gain") {
4115 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4118 } else if (p == "send-mtc") {
4120 if (Config->get_send_mtc ()) {
4121 /* mark us ready to send */
4122 next_quarter_frame_to_send = 0;
4125 } else if (p == "send-mmc") {
4127 _mmc->enable_send (Config->get_send_mmc ());
4129 } else if (p == "jack-time-master") {
4131 engine().reset_timebase ();
4133 } else if (p == "native-file-header-format") {
4135 if (!first_file_header_format_reset) {
4136 reset_native_file_format ();
4139 first_file_header_format_reset = false;
4141 } else if (p == "native-file-data-format") {
4143 if (!first_file_data_format_reset) {
4144 reset_native_file_format ();
4147 first_file_data_format_reset = false;
4149 } else if (p == "external-sync") {
4150 if (!config.get_external_sync()) {
4151 drop_sync_source ();
4153 switch_to_sync_source (Config->get_sync_source());
4155 } else if (p == "denormal-model") {
4157 } else if (p == "history-depth") {
4158 set_history_depth (Config->get_history_depth());
4159 } else if (p == "remote-model") {
4160 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4163 } else if (p == "initial-program-change") {
4165 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4168 buf[0] = MIDI::program; // channel zero by default
4169 buf[1] = (Config->get_initial_program_change() & 0x7f);
4171 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4173 } else if (p == "solo-mute-override") {
4174 // catch_up_on_solo_mute_override ();
4175 } else if (p == "listen-position" || p == "pfl-position") {
4176 listen_position_changed ();
4177 } else if (p == "solo-control-is-listen-control") {
4178 solo_control_mode_changed ();
4179 } else if (p == "solo-mute-gain") {
4180 _solo_cut_control->Changed (true, Controllable::NoGroup);
4181 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4182 last_timecode_valid = false;
4183 } else if (p == "playback-buffer-seconds") {
4184 AudioSource::allocate_working_buffers (frame_rate());
4185 } else if (p == "ltc-source-port") {
4186 reconnect_ltc_input ();
4187 } else if (p == "ltc-sink-port") {
4188 reconnect_ltc_output ();
4189 } else if (p == "timecode-generator-offset") {
4190 ltc_tx_parse_offset();
4191 } else if (p == "auto-return-target-list") {
4192 follow_playhead_priority ();
4199 Session::set_history_depth (uint32_t d)
4201 _history.set_depth (d);
4205 Session::load_diskstreams_2X (XMLNode const & node, int)
4208 XMLNodeConstIterator citer;
4210 clist = node.children();
4212 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4215 /* diskstreams added automatically by DiskstreamCreated handler */
4216 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4217 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4218 _diskstreams_2X.push_back (dsp);
4220 error << _("Session: unknown diskstream type in XML") << endmsg;
4224 catch (failed_constructor& err) {
4225 error << _("Session: could not load diskstream via XML state") << endmsg;
4233 /** Connect things to the MMC object */
4235 Session::setup_midi_machine_control ()
4237 _mmc = new MIDI::MachineControl;
4239 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4240 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4242 if (!async_out || !async_out) {
4246 /* XXXX argh, passing raw pointers back into libmidi++ */
4248 MIDI::Port* mmc_in = async_in.get();
4249 MIDI::Port* mmc_out = async_out.get();
4251 _mmc->set_ports (mmc_in, mmc_out);
4253 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4254 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4255 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4256 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4257 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4258 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4259 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4260 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4261 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4262 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4263 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4264 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4265 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4267 /* also handle MIDI SPP because its so common */
4269 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4270 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4271 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4274 boost::shared_ptr<Controllable>
4275 Session::solo_cut_control() const
4277 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4278 * controls in Ardour that currently get presented to the user in the GUI that require
4279 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4281 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4282 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4285 return _solo_cut_control;
4289 Session::save_snapshot_name (const std::string & n)
4291 /* assure Stateful::_instant_xml is loaded
4292 * add_instant_xml() only adds to existing data and defaults
4293 * to use an empty Tree otherwise
4295 instant_xml ("LastUsedSnapshot");
4297 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4298 last_used_snapshot->set_property ("name", n);
4299 add_instant_xml (*last_used_snapshot, false);
4303 Session::set_snapshot_name (const std::string & n)
4305 _current_snapshot_name = n;
4306 save_snapshot_name (n);
4310 Session::rename (const std::string& new_name)
4312 string legal_name = legalize_for_path (new_name);
4318 string const old_sources_root = _session_dir->sources_root();
4320 if (!_writable || (_state_of_the_state & CannotSave)) {
4321 error << _("Cannot rename read-only session.") << endmsg;
4322 return 0; // don't show "messed up" warning
4324 if (record_status() == Recording) {
4325 error << _("Cannot rename session while recording") << endmsg;
4326 return 0; // don't show "messed up" warning
4329 StateProtector stp (this);
4334 * interchange subdirectory
4338 * Backup files are left unchanged and not renamed.
4341 /* Windows requires that we close all files before attempting the
4342 * rename. This works on other platforms, but isn't necessary there.
4343 * Leave it in place for all platforms though, since it may help
4344 * catch issues that could arise if the way Source files work ever
4345 * change (since most developers are not using Windows).
4348 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4349 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4355 /* pass one: not 100% safe check that the new directory names don't
4359 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4363 /* this is a stupid hack because Glib::path_get_dirname() is
4364 * lexical-only, and so passing it /a/b/c/ gives a different
4365 * result than passing it /a/b/c ...
4368 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4369 oldstr = oldstr.substr (0, oldstr.length() - 1);
4372 string base = Glib::path_get_dirname (oldstr);
4374 newstr = Glib::build_filename (base, legal_name);
4376 cerr << "Looking for " << newstr << endl;
4378 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4379 cerr << " exists\n";
4388 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4394 /* this is a stupid hack because Glib::path_get_dirname() is
4395 * lexical-only, and so passing it /a/b/c/ gives a different
4396 * result than passing it /a/b/c ...
4399 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4400 oldstr = oldstr.substr (0, oldstr.length() - 1);
4403 string base = Glib::path_get_dirname (oldstr);
4404 newstr = Glib::build_filename (base, legal_name);
4406 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4408 cerr << "Rename " << oldstr << " => " << newstr << endl;
4409 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4410 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4411 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4415 /* Reset path in "session dirs" */
4420 /* reset primary SessionDirectory object */
4423 (*_session_dir) = newstr;
4428 /* now rename directory below session_dir/interchange */
4430 string old_interchange_dir;
4431 string new_interchange_dir;
4433 /* use newstr here because we renamed the path
4434 * (folder/directory) that used to be oldstr to newstr above
4437 v.push_back (newstr);
4438 v.push_back (interchange_dir_name);
4439 v.push_back (Glib::path_get_basename (oldstr));
4441 old_interchange_dir = Glib::build_filename (v);
4444 v.push_back (newstr);
4445 v.push_back (interchange_dir_name);
4446 v.push_back (legal_name);
4448 new_interchange_dir = Glib::build_filename (v);
4450 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4452 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4453 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4454 old_interchange_dir, new_interchange_dir,
4457 error << string_compose (_("renaming %s as %2 failed (%3)"),
4458 old_interchange_dir, new_interchange_dir,
4467 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4468 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4470 cerr << "Rename " << oldstr << " => " << newstr << endl;
4472 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4473 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4474 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4480 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4482 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4483 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4485 cerr << "Rename " << oldstr << " => " << newstr << endl;
4487 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4488 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4489 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4494 /* remove old name from recent sessions */
4495 remove_recent_sessions (_path);
4498 /* update file source paths */
4500 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4501 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4503 string p = fs->path ();
4504 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4506 SourceFactory::setup_peakfile(i->second, true);
4510 set_snapshot_name (new_name);
4515 /* save state again to get everything just right */
4517 save_state (_current_snapshot_name);
4519 /* add to recent sessions */
4521 store_recent_sessions (new_name, _path);
4527 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4529 bool found_sr = false;
4530 bool found_data_format = false;
4531 program_version = "";
4533 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4537 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4541 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4544 xmlFreeParserCtxt(ctxt);
4548 xmlNodePtr node = xmlDocGetRootElement(doc);
4551 xmlFreeParserCtxt(ctxt);
4559 for (attr = node->properties; attr; attr = attr->next) {
4560 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4561 sample_rate = atoi ((char*)attr->children->content);
4566 node = node->children;
4567 while (node != NULL) {
4568 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4569 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4571 program_version = string ((const char*)val);
4572 size_t sep = program_version.find_first_of("-");
4573 if (sep != string::npos) {
4574 program_version = program_version.substr (0, sep);
4579 if (strcmp((const char*) node->name, "Config")) {
4583 for (node = node->children; node; node = node->next) {
4584 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4585 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4587 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4589 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4591 found_data_format = true;
4601 xmlFreeParserCtxt(ctxt);
4604 return !(found_sr && found_data_format); // zero if they are both found
4608 Session::get_snapshot_from_instant (const std::string& session_dir)
4610 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4612 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4617 if (!tree.read (instant_xml_path)) {
4621 XMLProperty const * prop;
4622 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4623 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4624 return prop->value();
4630 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4631 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4634 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4638 SourcePathMap source_path_map;
4640 boost::shared_ptr<AudioFileSource> afs;
4645 Glib::Threads::Mutex::Lock lm (source_lock);
4647 cerr << " total sources = " << sources.size();
4649 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4650 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4656 if (fs->within_session()) {
4660 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4661 source_path_map[fs->path()].push_back (fs);
4663 SeveralFileSources v;
4665 source_path_map.insert (make_pair (fs->path(), v));
4671 cerr << " fsources = " << total << endl;
4673 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4675 /* tell caller where we are */
4677 string old_path = i->first;
4679 callback (n, total, old_path);
4681 cerr << old_path << endl;
4685 switch (i->second.front()->type()) {
4686 case DataType::AUDIO:
4687 new_path = new_audio_source_path_for_embedded (old_path);
4690 case DataType::MIDI:
4691 /* XXX not implemented yet */
4695 if (new_path.empty()) {
4699 cerr << "Move " << old_path << " => " << new_path << endl;
4701 if (!copy_file (old_path, new_path)) {
4702 cerr << "failed !\n";
4706 /* make sure we stop looking in the external
4707 dir/folder. Remember, this is an all-or-nothing
4708 operations, it doesn't merge just some files.
4710 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4712 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4713 (*f)->set_path (new_path);
4718 save_state ("", false, false);
4724 bool accept_all_files (string const &, void *)
4730 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4732 /* 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.
4737 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4739 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4741 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4743 v.push_back (new_session_folder); /* full path */
4744 v.push_back (interchange_dir_name);
4745 v.push_back (new_session_path); /* just one directory/folder */
4746 v.push_back (typedir);
4747 v.push_back (Glib::path_get_basename (old_path));
4749 return Glib::build_filename (v);
4753 Session::save_as (SaveAs& saveas)
4755 vector<string> files;
4756 string current_folder = Glib::path_get_dirname (_path);
4757 string new_folder = legalize_for_path (saveas.new_name);
4758 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4759 int64_t total_bytes = 0;
4763 int32_t internal_file_cnt = 0;
4765 vector<string> do_not_copy_extensions;
4766 do_not_copy_extensions.push_back (statefile_suffix);
4767 do_not_copy_extensions.push_back (pending_suffix);
4768 do_not_copy_extensions.push_back (backup_suffix);
4769 do_not_copy_extensions.push_back (temp_suffix);
4770 do_not_copy_extensions.push_back (history_suffix);
4772 /* get total size */
4774 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4776 /* need to clear this because
4777 * find_files_matching_filter() is cumulative
4782 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4784 all += files.size();
4786 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4788 g_stat ((*i).c_str(), &gsb);
4789 total_bytes += gsb.st_size;
4793 /* save old values so we can switch back if we are not switching to the new session */
4795 string old_path = _path;
4796 string old_name = _name;
4797 string old_snapshot = _current_snapshot_name;
4798 string old_sd = _session_dir->root_path();
4799 vector<string> old_search_path[DataType::num_types];
4800 string old_config_search_path[DataType::num_types];
4802 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4803 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4804 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4805 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4807 /* switch session directory */
4809 (*_session_dir) = to_dir;
4811 /* create new tree */
4813 if (!_session_dir->create()) {
4814 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4819 /* copy all relevant files. Find each location in session_dirs,
4820 * and copy files from there to target.
4823 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4825 /* need to clear this because
4826 * find_files_matching_filter() is cumulative
4831 const size_t prefix_len = (*sd).path.size();
4833 /* Work just on the files within this session dir */
4835 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4837 /* add dir separator to protect against collisions with
4838 * track names (e.g. track named "audiofiles" or
4842 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4843 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4844 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4846 /* copy all the files. Handling is different for media files
4847 than others because of the *silly* subtree we have below the interchange
4848 folder. That really was a bad idea, but I'm not fixing it as part of
4849 implementing ::save_as().
4852 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4854 std::string from = *i;
4857 string filename = Glib::path_get_basename (from);
4858 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4859 if (filename == ".DS_STORE") {
4864 if (from.find (audiofile_dir_string) != string::npos) {
4866 /* audio file: only copy if asked */
4868 if (saveas.include_media && saveas.copy_media) {
4870 string to = make_new_media_path (*i, to_dir, new_folder);
4872 info << "media file copying from " << from << " to " << to << endmsg;
4874 if (!copy_file (from, to)) {
4875 throw Glib::FileError (Glib::FileError::IO_ERROR,
4876 string_compose(_("\ncopying \"%1\" failed !"), from));
4880 /* we found media files inside the session folder */
4882 internal_file_cnt++;
4884 } else if (from.find (midifile_dir_string) != string::npos) {
4886 /* midi file: always copy unless
4887 * creating an empty new session
4890 if (saveas.include_media) {
4892 string to = make_new_media_path (*i, to_dir, new_folder);
4894 info << "media file copying from " << from << " to " << to << endmsg;
4896 if (!copy_file (from, to)) {
4897 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4901 /* we found media files inside the session folder */
4903 internal_file_cnt++;
4905 } else if (from.find (analysis_dir_string) != string::npos) {
4907 /* make sure analysis dir exists in
4908 * new session folder, but we're not
4909 * copying analysis files here, see
4913 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4918 /* normal non-media file. Don't copy state, history, etc.
4921 bool do_copy = true;
4923 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4924 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4925 /* end of filename matches extension, do not copy file */
4931 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4932 /* don't copy peakfiles if
4933 * we're not copying media
4939 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4941 info << "attempting to make directory/folder " << to << endmsg;
4943 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4944 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4947 info << "attempting to copy " << from << " to " << to << endmsg;
4949 if (!copy_file (from, to)) {
4950 throw Glib::FileError (Glib::FileError::IO_ERROR,
4951 string_compose(_("\ncopying \"%1\" failed !"), from));
4956 /* measure file size even if we're not going to copy so that our Progress
4957 signals are correct, since we included these do-not-copy files
4958 in the computation of the total size and file count.
4962 g_stat (from.c_str(), &gsb);
4963 copied += gsb.st_size;
4966 double fraction = (double) copied / total_bytes;
4968 bool keep_going = true;
4970 if (saveas.copy_media) {
4972 /* no need or expectation of this if
4973 * media is not being copied, because
4974 * it will be fast(ish).
4977 /* tell someone "X percent, file M of N"; M is one-based */
4979 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4987 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4993 /* copy optional folders, if any */
4995 string old = plugins_dir ();
4996 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4997 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4998 copy_files (old, newdir);
5001 old = externals_dir ();
5002 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5003 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5004 copy_files (old, newdir);
5007 old = automation_dir ();
5008 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5009 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5010 copy_files (old, newdir);
5013 if (saveas.include_media) {
5015 if (saveas.copy_media) {
5016 #ifndef PLATFORM_WINDOWS
5017 /* There are problems with analysis files on
5018 * Windows, because they used a colon in their
5019 * names as late as 4.0. Colons are not legal
5020 * under Windows even if NTFS allows them.
5022 * This is a tricky problem to solve so for
5023 * just don't copy these files. They will be
5024 * regenerated as-needed anyway, subject to the
5025 * existing issue that the filenames will be
5026 * rejected by Windows, which is a separate
5027 * problem (though related).
5030 /* only needed if we are copying media, since the
5031 * analysis data refers to media data
5034 old = analysis_dir ();
5035 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5036 string newdir = Glib::build_filename (to_dir, "analysis");
5037 copy_files (old, newdir);
5039 #endif /* PLATFORM_WINDOWS */
5044 set_snapshot_name (saveas.new_name);
5045 _name = saveas.new_name;
5047 if (saveas.include_media && !saveas.copy_media) {
5049 /* reset search paths of the new session (which we're pretending to be right now) to
5050 include the original session search path, so we can still find all audio.
5053 if (internal_file_cnt) {
5054 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5055 ensure_search_path_includes (*s, DataType::AUDIO);
5056 cerr << "be sure to include " << *s << " for audio" << endl;
5059 /* we do not do this for MIDI because we copy
5060 all MIDI files if saveas.include_media is
5066 bool was_dirty = dirty ();
5068 save_default_options ();
5070 if (saveas.copy_media && saveas.copy_external) {
5071 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5072 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5076 saveas.final_session_folder_name = _path;
5078 store_recent_sessions (_name, _path);
5080 if (!saveas.switch_to) {
5082 /* save the new state */
5084 save_state ("", false, false, !saveas.include_media);
5086 /* switch back to the way things were */
5090 set_snapshot_name (old_snapshot);
5092 (*_session_dir) = old_sd;
5098 if (internal_file_cnt) {
5099 /* reset these to their original values */
5100 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5101 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5106 /* prune session dirs, and update disk space statistics
5111 session_dirs.clear ();
5112 session_dirs.push_back (sp);
5113 refresh_disk_space ();
5115 _writable = exists_and_writable (_path);
5117 /* ensure that all existing tracks reset their current capture source paths
5119 reset_write_sources (true, true);
5121 /* creating new write sources marks the session as
5122 dirty. If the new session is empty, then
5123 save_state() thinks we're saving a template and will
5124 not mark the session as clean. So do that here,
5125 before we save state.
5128 if (!saveas.include_media) {
5129 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5132 save_state ("", false, false, !saveas.include_media);
5134 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5135 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5138 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5139 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5145 if (fs->within_session()) {
5146 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5147 fs->set_path (newpath);
5152 } catch (Glib::FileError& e) {
5154 saveas.failure_message = e.what();
5156 /* recursively remove all the directories */
5158 remove_directory (to_dir);
5166 saveas.failure_message = _("unknown reason");
5168 /* recursively remove all the directories */
5170 remove_directory (to_dir);
5180 static void set_progress (Progress* p, size_t n, size_t t)
5182 p->set_progress (float (n) / float(t));
5186 Session::archive_session (const std::string& dest,
5187 const std::string& name,
5188 ArchiveEncode compress_audio,
5189 bool only_used_sources,
5192 if (dest.empty () || name.empty ()) {
5196 /* save current values */
5197 bool was_dirty = dirty ();
5198 string old_path = _path;
5199 string old_name = _name;
5200 string old_snapshot = _current_snapshot_name;
5201 string old_sd = _session_dir->root_path();
5202 string old_config_search_path[DataType::num_types];
5203 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5204 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5206 /* ensure that session-path is included in search-path */
5208 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5209 if ((*sd).path == old_path) {
5217 /* create temporary dir to save session to */
5218 #ifdef PLATFORM_WINDOWS
5219 char tmp[256] = "C:\\TEMP\\";
5220 GetTempPath (sizeof (tmp), tmp);
5222 char const* tmp = getenv("TMPDIR");
5227 if ((strlen (tmp) + 21) > 1024) {
5232 strcpy (tmptpl, tmp);
5233 strcat (tmptpl, "ardourarchive-XXXXXX");
5234 char* tmpdir = g_mkdtemp (tmptpl);
5240 std::string to_dir = std::string (tmpdir);
5242 /* switch session directory temporarily */
5243 (*_session_dir) = to_dir;
5245 if (!_session_dir->create()) {
5246 (*_session_dir) = old_sd;
5247 remove_directory (to_dir);
5251 /* prepare archive */
5252 string archive = Glib::build_filename (dest, name + ".tar.xz");
5254 PBD::ScopedConnectionList progress_connection;
5255 PBD::FileArchive ar (archive);
5257 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5260 /* collect files to archive */
5261 std::map<string,string> filemap;
5263 vector<string> do_not_copy_extensions;
5264 do_not_copy_extensions.push_back (statefile_suffix);
5265 do_not_copy_extensions.push_back (pending_suffix);
5266 do_not_copy_extensions.push_back (backup_suffix);
5267 do_not_copy_extensions.push_back (temp_suffix);
5268 do_not_copy_extensions.push_back (history_suffix);
5270 vector<string> blacklist_dirs;
5271 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5272 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5273 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5274 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5275 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5276 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5278 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5279 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5281 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5282 if (only_used_sources) {
5283 playlists->sync_all_regions_with_regions ();
5284 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5287 // collect audio sources for this session, calc total size for encoding
5288 // add option to only include *used* sources (see Session::cleanup_sources)
5289 size_t total_size = 0;
5291 Glib::Threads::Mutex::Lock lm (source_lock);
5292 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5293 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5294 if (!afs || afs->readable_length () == 0) {
5298 if (only_used_sources) {
5302 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5307 std::string from = afs->path();
5309 if (compress_audio != NO_ENCODE) {
5310 total_size += afs->readable_length ();
5312 if (afs->within_session()) {
5313 filemap[from] = make_new_media_path (from, name, name);
5315 filemap[from] = make_new_media_path (from, name, name);
5316 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5323 if (compress_audio != NO_ENCODE) {
5325 progress->set_progress (2); // set to "encoding"
5326 progress->set_progress (0);
5329 Glib::Threads::Mutex::Lock lm (source_lock);
5330 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5331 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5332 if (!afs || afs->readable_length () == 0) {
5336 if (only_used_sources) {
5340 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5345 orig_sources[afs] = afs->path();
5346 orig_gain[afs] = afs->gain();
5348 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5349 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5350 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5353 progress->descend ((float)afs->readable_length () / total_size);
5357 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5358 afs->replace_file (new_path);
5359 afs->set_gain (ns->gain(), true);
5362 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5366 progress->ascend ();
5372 progress->set_progress (-1); // set to "archiving"
5373 progress->set_progress (0);
5376 /* index files relevant for this session */
5377 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5378 vector<string> files;
5380 size_t prefix_len = (*sd).path.size();
5381 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5385 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5387 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5388 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5389 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5391 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5392 std::string from = *i;
5395 string filename = Glib::path_get_basename (from);
5396 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5397 if (filename == ".DS_STORE") {
5402 if (from.find (audiofile_dir_string) != string::npos) {
5404 } else if (from.find (midifile_dir_string) != string::npos) {
5405 filemap[from] = make_new_media_path (from, name, name);
5406 } else if (from.find (videofile_dir_string) != string::npos) {
5407 filemap[from] = make_new_media_path (from, name, name);
5409 bool do_copy = true;
5410 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5411 if (from.find (*v) != string::npos) {
5416 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5417 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5424 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5430 /* write session file */
5432 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5434 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5437 save_default_options ();
5439 size_t prefix_len = _path.size();
5440 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5444 /* collect session-state files */
5445 vector<string> files;
5446 do_not_copy_extensions.clear ();
5447 do_not_copy_extensions.push_back (history_suffix);
5449 blacklist_dirs.clear ();
5450 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5452 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5453 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5454 std::string from = *i;
5455 bool do_copy = true;
5456 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5457 if (from.find (*v) != string::npos) {
5462 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5463 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5469 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5473 /* restore original values */
5476 set_snapshot_name (old_snapshot);
5477 (*_session_dir) = old_sd;
5481 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5482 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5484 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5485 i->first->replace_file (i->second);
5487 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5488 i->first->set_gain (i->second, true);
5491 int rv = ar.create (filemap);
5492 remove_directory (to_dir);
5498 Session::undo (uint32_t n)
5500 if (actively_recording()) {
5508 Session::redo (uint32_t n)
5510 if (actively_recording()) {