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));
269 /* MidiClock requires a tempo map */
272 midi_clock = new MidiClockTicker ();
273 midi_clock->set_session (this);
275 /* crossfades require sample rate knowledge */
277 SndFileSource::setup_standard_crossfades (*this, frame_rate());
278 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
279 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
281 AudioDiskstream::allocate_working_buffers();
282 refresh_disk_space ();
284 /* we're finally ready to call set_state() ... all objects have
285 * been created, the engine is running.
289 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
290 error << _("Could not set session state from XML") << endmsg;
294 // set_state() will call setup_raid_path(), but if it's a new session we need
295 // to call setup_raid_path() here.
296 setup_raid_path (_path);
301 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
302 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
304 Config->map_parameters (ff);
305 config.map_parameters (ft);
306 _butler->map_parameters ();
308 /* Reset all panners */
310 Delivery::reset_panners ();
312 /* this will cause the CPM to instantiate any protocols that are in use
313 * (or mandatory), which will pass it this Session, and then call
314 * set_state() on each instantiated protocol to match stored state.
317 ControlProtocolManager::instance().set_session (this);
319 /* This must be done after the ControlProtocolManager set_session above,
320 as it will set states for ports which the ControlProtocolManager creates.
323 // XXX set state of MIDI::Port's
324 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
326 /* And this must be done after the MIDI::Manager::set_port_states as
327 * it will try to make connections whose details are loaded by set_port_states.
332 /* Let control protocols know that we are now all connected, so they
333 * could start talking to surfaces if they want to.
336 ControlProtocolManager::instance().midi_connectivity_established ();
338 if (_is_new && !no_auto_connect()) {
339 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
340 auto_connect_master_bus ();
343 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
345 /* update latencies */
347 initialize_latencies ();
349 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
350 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
351 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
353 } catch (AudioEngine::PortRegistrationFailure& err) {
354 /* handle this one in a different way than all others, so that its clear what happened */
355 error << err.what() << endmsg;
357 } catch (std::exception const & e) {
358 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
361 error << _("Unknown exception during session setup") << endmsg;
365 BootMessage (_("Reset Remote Controls"));
367 // send_full_time_code (0);
368 _engine.transport_locate (0);
370 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
371 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
373 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
376 /* initial program change will be delivered later; see ::config_changed() */
378 _state_of_the_state = Clean;
380 Port::set_connecting_blocked (false);
382 DirtyChanged (); /* EMIT SIGNAL */
386 } else if (state_was_pending) {
388 remove_pending_capture_state ();
389 state_was_pending = false;
392 /* Now, finally, we can fill the playback buffers */
394 BootMessage (_("Filling playback buffers"));
396 boost::shared_ptr<RouteList> rl = routes.reader();
397 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
398 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
399 if (trk && !trk->hidden()) {
400 trk->seek (_transport_frame, true);
408 Session::session_loaded ()
412 _state_of_the_state = Clean;
414 DirtyChanged (); /* EMIT SIGNAL */
418 } else if (state_was_pending) {
420 remove_pending_capture_state ();
421 state_was_pending = false;
424 /* Now, finally, we can fill the playback buffers */
426 BootMessage (_("Filling playback buffers"));
427 force_locate (_transport_frame, false);
431 Session::raid_path () const
433 Searchpath raid_search_path;
435 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
436 raid_search_path += (*i).path;
439 return raid_search_path.to_string ();
443 Session::setup_raid_path (string path)
452 session_dirs.clear ();
454 Searchpath search_path(path);
455 Searchpath sound_search_path;
456 Searchpath midi_search_path;
458 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
460 sp.blocks = 0; // not needed
461 session_dirs.push_back (sp);
463 SessionDirectory sdir(sp.path);
465 sound_search_path += sdir.sound_path ();
466 midi_search_path += sdir.midi_path ();
469 // reset the round-robin soundfile path thingie
470 last_rr_session_dir = session_dirs.begin();
474 Session::path_is_within_session (const std::string& path)
476 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
477 if (PBD::path_is_within (i->path, path)) {
485 Session::ensure_subdirs ()
489 dir = session_directory().peak_path();
491 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
492 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
496 dir = session_directory().sound_path();
498 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
499 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
503 dir = session_directory().midi_path();
505 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
506 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
510 dir = session_directory().dead_path();
512 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
513 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
517 dir = session_directory().export_path();
519 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
520 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
524 dir = analysis_dir ();
526 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
527 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
531 dir = plugins_dir ();
533 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
534 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
538 dir = externals_dir ();
540 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
541 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
548 /** @param session_template directory containing session template, or empty.
549 * Caller must not hold process lock.
552 Session::create (const string& session_template, BusProfile* bus_profile)
554 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
555 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
559 if (ensure_subdirs ()) {
563 _writable = exists_and_writable (_path);
565 if (!session_template.empty()) {
566 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
568 FILE* in = g_fopen (in_path.c_str(), "rb");
571 /* no need to call legalize_for_path() since the string
572 * in session_template is already a legal path name
574 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
576 FILE* out = g_fopen (out_path.c_str(), "wb");
580 stringstream new_session;
583 size_t charsRead = fread (buf, sizeof(char), 1024, in);
586 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
591 if (charsRead == 0) {
594 new_session.write (buf, charsRead);
598 string file_contents = new_session.str();
599 size_t writeSize = file_contents.length();
600 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
601 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
609 if (!ARDOUR::Profile->get_trx()) {
610 /* Copy plugin state files from template to new session */
611 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
612 copy_recurse (template_plugins, plugins_dir ());
618 error << string_compose (_("Could not open %1 for writing session template"), out_path)
625 error << string_compose (_("Could not open session template %1 for reading"), in_path)
632 if (Profile->get_trx()) {
634 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
635 * Remember that this is a brand new session. Sessions
636 * loaded from saved state will get this range from the saved state.
639 set_session_range_location (0, 0);
641 /* Initial loop location, from absolute zero, length 10 seconds */
643 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
644 _locations->add (loc, true);
645 set_auto_loop_location (loc);
648 _state_of_the_state = Clean;
650 /* set up Master Out and Monitor Out if necessary */
655 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
657 // Waves Tracks: always create master bus for Tracks
658 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
659 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
667 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
668 r->input()->ensure_io (count, false, this);
669 r->output()->ensure_io (count, false, this);
675 /* prohibit auto-connect to master, because there isn't one */
676 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
680 add_routes (rl, false, false, false, PresentationInfo::max_order);
683 // Waves Tracks: Skip this. Always use autoconnection for Tracks
684 if (!ARDOUR::Profile->get_trx()) {
686 /* this allows the user to override settings with an environment variable.
689 if (no_auto_connect()) {
690 bus_profile->input_ac = AutoConnectOption (0);
691 bus_profile->output_ac = AutoConnectOption (0);
694 Config->set_input_auto_connect (bus_profile->input_ac);
695 Config->set_output_auto_connect (bus_profile->output_ac);
699 if (Config->get_use_monitor_bus() && bus_profile) {
700 add_monitor_section ();
707 Session::maybe_write_autosave()
709 if (dirty() && record_status() != Recording) {
710 save_state("", true);
715 Session::remove_pending_capture_state ()
717 std::string pending_state_file_path(_session_dir->root_path());
719 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
721 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
723 if (g_remove (pending_state_file_path.c_str()) != 0) {
724 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
725 pending_state_file_path, g_strerror (errno)) << endmsg;
729 /** Rename a state file.
730 * @param old_name Old snapshot name.
731 * @param new_name New snapshot name.
734 Session::rename_state (string old_name, string new_name)
736 if (old_name == _current_snapshot_name || old_name == _name) {
737 /* refuse to rename the current snapshot or the "main" one */
741 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
742 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
744 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
745 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
747 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
748 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
749 old_name, new_name, g_strerror(errno)) << endmsg;
753 /** Remove a state file.
754 * @param snapshot_name Snapshot name.
757 Session::remove_state (string snapshot_name)
759 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
760 // refuse to remove the current snapshot or the "main" one
764 std::string xml_path(_session_dir->root_path());
766 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
768 if (!create_backup_file (xml_path)) {
769 // don't remove it if a backup can't be made
770 // create_backup_file will log the error.
775 if (g_remove (xml_path.c_str()) != 0) {
776 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
777 xml_path, g_strerror (errno)) << endmsg;
781 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
783 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
785 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
788 std::string xml_path(_session_dir->root_path());
790 /* prevent concurrent saves from different threads */
792 Glib::Threads::Mutex::Lock lm (save_state_lock);
794 if (!_writable || (_state_of_the_state & CannotSave)) {
798 if (g_atomic_int_get(&_suspend_save)) {
802 _save_queued = false;
804 snapshot_t fork_state = NormalSave;
805 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) {
806 /* snapshot, close midi */
807 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
811 const int64_t save_start_time = g_get_monotonic_time();
814 /* tell sources we're saving first, in case they write out to a new file
815 * which should be saved with the state rather than the old one */
816 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
818 i->second->session_saved();
819 } catch (Evoral::SMF::FileError& e) {
820 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
824 SessionSaveUnderway (); /* EMIT SIGNAL */
826 bool mark_as_clean = true;
828 if (!snapshot_name.empty() && !switch_to_snapshot) {
829 mark_as_clean = false;
833 mark_as_clean = false;
834 tree.set_root (&get_template());
836 tree.set_root (&state (true, fork_state));
839 if (snapshot_name.empty()) {
840 snapshot_name = _current_snapshot_name;
841 } else if (switch_to_snapshot) {
842 set_snapshot_name (snapshot_name);
845 assert (!snapshot_name.empty());
849 /* proper save: use statefile_suffix (.ardour in English) */
851 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
853 /* make a backup copy of the old file */
855 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
856 // create_backup_file will log the error
862 /* pending save: use pending_suffix (.pending in English) */
863 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
866 std::string tmp_path(_session_dir->root_path());
867 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
869 cerr << "actually writing state to " << tmp_path << endl;
871 if (!tree.write (tmp_path)) {
872 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
873 if (g_remove (tmp_path.c_str()) != 0) {
874 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
875 tmp_path, g_strerror (errno)) << endmsg;
881 cerr << "renaming state to " << xml_path << endl;
883 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
884 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
885 tmp_path, xml_path, g_strerror(errno)) << endmsg;
886 if (g_remove (tmp_path.c_str()) != 0) {
887 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
888 tmp_path, g_strerror (errno)) << endmsg;
896 save_history (snapshot_name);
899 bool was_dirty = dirty();
901 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
904 DirtyChanged (); /* EMIT SIGNAL */
908 StateSaved (snapshot_name); /* EMIT SIGNAL */
912 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
913 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
919 Session::restore_state (string snapshot_name)
921 if (load_state (snapshot_name) == 0) {
922 set_state (*state_tree->root(), Stateful::loading_state_version);
929 Session::load_state (string snapshot_name)
934 state_was_pending = false;
936 /* check for leftover pending state from a crashed capture attempt */
938 std::string xmlpath(_session_dir->root_path());
939 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
941 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
943 /* there is pending state from a crashed capture attempt */
945 boost::optional<int> r = AskAboutPendingState();
946 if (r.get_value_or (1)) {
947 state_was_pending = true;
951 if (!state_was_pending) {
952 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
955 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
956 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
957 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
958 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
963 state_tree = new XMLTree;
967 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
969 if (!state_tree->read (xmlpath)) {
970 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
976 XMLNode const & root (*state_tree->root());
978 if (root.name() != X_("Session")) {
979 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
986 if (root.get_property ("version", version)) {
987 if (version.find ('.') != string::npos) {
988 /* old school version format */
989 if (version[0] == '2') {
990 Stateful::loading_state_version = 2000;
992 Stateful::loading_state_version = 3000;
995 Stateful::loading_state_version = string_to<int32_t>(version);
998 /* no version implies very old version of Ardour */
999 Stateful::loading_state_version = 1000;
1002 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1004 std::string backup_path(_session_dir->root_path());
1005 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1006 backup_path = Glib::build_filename (backup_path, backup_filename);
1008 // only create a backup for a given statefile version once
1010 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1012 VersionMismatch (xmlpath, backup_path);
1014 if (!copy_file (xmlpath, backup_path)) {;
1020 save_snapshot_name (snapshot_name);
1026 Session::load_options (const XMLNode& node)
1028 config.set_variables (node);
1033 Session::save_default_options ()
1035 return config.save_state();
1039 Session::get_state()
1045 Session::get_template()
1047 /* if we don't disable rec-enable, diskstreams
1048 will believe they need to store their capture
1049 sources in their state node.
1052 disable_record (false);
1054 return state(false);
1057 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1058 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1061 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1063 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1066 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1070 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1073 XMLNode* node = new XMLNode("TrackState"); // XXX
1076 PlaylistSet playlists; // SessionPlaylists
1079 // these will work with new_route_from_template()
1080 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1081 child = node->add_child ("Routes");
1082 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1083 if ((*i)->is_auditioner()) {
1086 if ((*i)->is_master() || (*i)->is_monitor()) {
1089 child->add_child_nocopy ((*i)->get_state());
1090 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1092 playlists.insert (track->playlist ());
1096 // on load, Regions in the playlists need to resolve and map Source-IDs
1097 // also playlist needs to be merged or created with new-name..
1098 // ... and Diskstream in tracks adjusted to use the correct playlist
1099 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1100 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1101 child->add_child_nocopy ((*i)->get_state ());
1102 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1103 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1104 const Region::SourceList& sl = (*s)->sources ();
1105 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1106 sources.insert (*sli);
1111 child = node->add_child ("Sources");
1112 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1113 child->add_child_nocopy ((*i)->get_state ());
1114 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1116 #ifdef PLATFORM_WINDOWS
1119 string p = fs->path ();
1120 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1124 std::string sn = Glib::build_filename (path, "share.axml");
1127 tree.set_root (node);
1128 return tree.write (sn.c_str());
1133 struct route_id_compare {
1135 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1137 return r1->id () < r2->id ();
1143 Session::state (bool full_state, snapshot_t snapshot_type)
1146 XMLNode* node = new XMLNode("Session");
1149 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1151 child = node->add_child ("ProgramVersion");
1152 child->set_property("created-with", created_with);
1154 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1155 child->set_property("modified-with", modified_with);
1157 /* store configuration settings */
1161 node->set_property ("name", _name);
1162 node->set_property ("sample-rate", _base_frame_rate);
1164 if (session_dirs.size() > 1) {
1168 vector<space_and_path>::iterator i = session_dirs.begin();
1169 vector<space_and_path>::iterator next;
1171 ++i; /* skip the first one */
1175 while (i != session_dirs.end()) {
1179 if (next != session_dirs.end()) {
1180 p += G_SEARCHPATH_SEPARATOR;
1189 child = node->add_child ("Path");
1190 child->add_content (p);
1192 node->set_property ("end-is-free", _session_range_end_is_free);
1195 /* save the ID counter */
1197 node->set_property ("id-counter", ID::counter());
1199 node->set_property ("name-counter", name_id_counter ());
1201 /* save the event ID counter */
1203 node->set_property ("event-counter", Evoral::event_id_counter());
1205 /* save the VCA counter */
1207 node->set_property ("vca-counter", VCA::get_next_vca_number());
1209 /* various options */
1211 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1212 if (!midi_port_nodes.empty()) {
1213 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1214 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1215 midi_port_stuff->add_child_nocopy (**n);
1217 node->add_child_nocopy (*midi_port_stuff);
1220 XMLNode& cfgxml (config.get_variables ());
1222 /* exclude search-paths from template */
1223 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1224 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1225 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1227 node->add_child_nocopy (cfgxml);
1229 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1231 child = node->add_child ("Sources");
1234 Glib::Threads::Mutex::Lock sl (source_lock);
1236 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1238 /* Don't save information about non-file Sources, or
1239 * about non-destructive file sources that are empty
1240 * and unused by any regions.
1242 boost::shared_ptr<FileSource> fs;
1244 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1248 if (!fs->destructive()) {
1249 if (fs->empty() && !fs->used()) {
1254 if (snapshot_type != NormalSave && fs->within_session ()) {
1255 /* copy MIDI sources to new file
1257 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1258 * because the GUI (midi_region) has a direct pointer to the midi-model
1259 * of the source, as does UndoTransaction.
1261 * On the upside, .mid files are not kept open. The file is only open
1262 * when reading the model initially and when flushing the model to disk:
1263 * source->session_saved () or export.
1265 * We can change the _path of the existing source under the hood, keeping
1266 * all IDs, references and pointers intact.
1268 boost::shared_ptr<SMFSource> ms;
1269 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1270 const std::string ancestor_name = ms->ancestor_name();
1271 const std::string base = PBD::basename_nosuffix(ancestor_name);
1272 const string path = new_midi_source_path (base, false);
1274 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1275 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1276 Source::Lock lm (ms->mutex());
1278 // TODO special-case empty, removable() files: just create a new removable.
1279 // (load + write flushes the model and creates the file)
1281 ms->load_model (lm);
1283 if (ms->write_to (lm, newsrc, Evoral::MinBeats, Evoral::MaxBeats)) {
1284 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1286 if (snapshot_type == SnapshotKeep) {
1287 /* keep working on current session.
1289 * Save snapshot-state with the original filename.
1290 * Switch to use new path for future saves of the main session.
1292 child->add_child_nocopy (ms->get_state());
1296 * ~SMFSource unlinks removable() files.
1298 std::string npath (ms->path ());
1299 ms->replace_file (newsrc->path ());
1300 newsrc->replace_file (npath);
1302 if (snapshot_type == SwitchToSnapshot) {
1303 /* save and switch to snapshot.
1305 * Leave the old file in place (as is).
1306 * Snapshot uses new source directly
1308 child->add_child_nocopy (ms->get_state());
1315 child->add_child_nocopy (siter->second->get_state());
1319 child = node->add_child ("Regions");
1322 Glib::Threads::Mutex::Lock rl (region_lock);
1323 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1324 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1325 boost::shared_ptr<Region> r = i->second;
1326 /* only store regions not attached to playlists */
1327 if (r->playlist() == 0) {
1328 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1329 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1331 child->add_child_nocopy (r->get_state ());
1336 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1338 if (!cassocs.empty()) {
1339 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1341 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1342 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1343 can->set_property (X_("copy"), i->first->id());
1344 can->set_property (X_("original"), i->second->id());
1345 ca->add_child_nocopy (*can);
1352 node->add_child_nocopy (_selection->get_state());
1355 node->add_child_nocopy (_locations->get_state());
1358 Locations loc (*this);
1359 const bool was_dirty = dirty();
1360 // for a template, just create a new Locations, populate it
1361 // with the default start and end, and get the state for that.
1362 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1363 range->set (max_framepos, 0);
1365 XMLNode& locations_state = loc.get_state();
1367 if (ARDOUR::Profile->get_trx() && _locations) {
1368 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1369 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1370 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1371 locations_state.add_child_nocopy ((*i)->get_state ());
1375 node->add_child_nocopy (locations_state);
1377 /* adding a location above will have marked the session
1378 * dirty. This is an artifact, so fix it if the session wasn't
1383 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1387 child = node->add_child ("Bundles");
1389 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1390 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1391 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1393 child->add_child_nocopy (b->get_state());
1398 node->add_child_nocopy (_vca_manager->get_state());
1400 child = node->add_child ("Routes");
1402 boost::shared_ptr<RouteList> r = routes.reader ();
1404 route_id_compare cmp;
1405 RouteList xml_node_order (*r);
1406 xml_node_order.sort (cmp);
1408 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1409 if (!(*i)->is_auditioner()) {
1411 child->add_child_nocopy ((*i)->get_state());
1413 child->add_child_nocopy ((*i)->get_template());
1419 playlists->add_state (node, full_state);
1421 child = node->add_child ("RouteGroups");
1422 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1423 child->add_child_nocopy ((*i)->get_state());
1427 XMLNode* gain_child = node->add_child ("Click");
1428 gain_child->add_child_nocopy (_click_io->state (full_state));
1429 gain_child->add_child_nocopy (_click_gain->state (full_state));
1433 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1434 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1438 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1439 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1442 node->add_child_nocopy (_speakers->get_state());
1443 node->add_child_nocopy (_tempo_map->get_state());
1444 node->add_child_nocopy (get_control_protocol_state());
1447 node->add_child_copy (*_extra_xml);
1451 Glib::Threads::Mutex::Lock lm (lua_lock);
1454 luabridge::LuaRef savedstate ((*_lua_save)());
1455 saved = savedstate.cast<std::string>();
1457 lua.collect_garbage ();
1460 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1461 std::string b64s (b64);
1464 XMLNode* script_node = new XMLNode (X_("Script"));
1465 script_node->set_property (X_("lua"), LUA_VERSION);
1466 script_node->add_content (b64s);
1467 node->add_child_nocopy (*script_node);
1474 Session::get_control_protocol_state ()
1476 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1477 return cpm.get_state();
1481 Session::set_state (const XMLNode& node, int version)
1488 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1490 if (node.name() != X_("Session")) {
1491 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1495 node.get_property ("name", _name);
1497 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1499 _nominal_frame_rate = _base_frame_rate;
1501 assert (AudioEngine::instance()->running ());
1502 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1503 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1504 if (r.get_value_or (0)) {
1510 created_with = "unknown";
1511 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1512 child->get_property (X_("created-with"), created_with);
1515 setup_raid_path(_session_dir->root_path());
1517 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1520 if (node.get_property (X_("id-counter"), counter)) {
1521 ID::init_counter (counter);
1523 /* old sessions used a timebased counter, so fake
1524 * the startup ID counter based on a standard
1529 ID::init_counter (now);
1532 if (node.get_property (X_("name-counter"), counter)) {
1533 init_name_id_counter (counter);
1536 if (node.get_property (X_("event-counter"), counter)) {
1537 Evoral::init_event_id_counter (counter);
1540 if (node.get_property (X_("vca-counter"), counter)) {
1541 VCA::set_next_vca_number (counter);
1543 VCA::set_next_vca_number (1);
1546 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1547 _midi_ports->set_midi_port_states (child->children());
1550 IO::disable_connecting ();
1552 Stateful::save_extra_xml (node);
1554 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1555 load_options (*child);
1556 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1557 load_options (*child);
1559 error << _("Session: XML state has no options section") << endmsg;
1562 if (version >= 3000) {
1563 if ((child = find_named_node (node, "Metadata")) == 0) {
1564 warning << _("Session: XML state has no metadata section") << endmsg;
1565 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1570 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1571 _speakers->set_state (*child, version);
1574 if ((child = find_named_node (node, "Sources")) == 0) {
1575 error << _("Session: XML state has no sources section") << endmsg;
1577 } else if (load_sources (*child)) {
1581 if ((child = find_named_node (node, "TempoMap")) == 0) {
1582 error << _("Session: XML state has no Tempo Map section") << endmsg;
1584 } else if (_tempo_map->set_state (*child, version)) {
1588 if ((child = find_named_node (node, "Locations")) == 0) {
1589 error << _("Session: XML state has no locations section") << endmsg;
1591 } else if (_locations->set_state (*child, version)) {
1595 locations_changed ();
1597 if (_session_range_location) {
1598 AudioFileSource::set_header_position_offset (_session_range_location->start());
1601 if ((child = find_named_node (node, "Regions")) == 0) {
1602 error << _("Session: XML state has no Regions section") << endmsg;
1604 } else if (load_regions (*child)) {
1608 if ((child = find_named_node (node, "Playlists")) == 0) {
1609 error << _("Session: XML state has no playlists section") << endmsg;
1611 } else if (playlists->load (*this, *child)) {
1615 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1617 } else if (playlists->load_unused (*this, *child)) {
1621 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1622 if (load_compounds (*child)) {
1627 if (version >= 3000) {
1628 if ((child = find_named_node (node, "Bundles")) == 0) {
1629 warning << _("Session: XML state has no bundles section") << endmsg;
1632 /* We can't load Bundles yet as they need to be able
1633 * to convert from port names to Port objects, which can't happen until
1635 _bundle_xml_node = new XMLNode (*child);
1639 if (version < 3000) {
1640 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1641 error << _("Session: XML state has no diskstreams section") << endmsg;
1643 } else if (load_diskstreams_2X (*child, version)) {
1648 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1649 _vca_manager->set_state (*child, version);
1652 if ((child = find_named_node (node, "Routes")) == 0) {
1653 error << _("Session: XML state has no routes section") << endmsg;
1655 } else if (load_routes (*child, version)) {
1659 /* Now that we have Routes and masters loaded, connect them if appropriate */
1661 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1663 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1664 _diskstreams_2X.clear ();
1666 if (version >= 3000) {
1668 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1669 error << _("Session: XML state has no route groups section") << endmsg;
1671 } else if (load_route_groups (*child, version)) {
1675 } else if (version < 3000) {
1677 if ((child = find_named_node (node, "EditGroups")) == 0) {
1678 error << _("Session: XML state has no edit groups section") << endmsg;
1680 } else if (load_route_groups (*child, version)) {
1684 if ((child = find_named_node (node, "MixGroups")) == 0) {
1685 error << _("Session: XML state has no mix groups section") << endmsg;
1687 } else if (load_route_groups (*child, version)) {
1692 if ((child = find_named_node (node, "Click")) == 0) {
1693 warning << _("Session: XML state has no click section") << endmsg;
1694 } else if (_click_io) {
1695 setup_click_state (&node);
1698 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1699 ControlProtocolManager::instance().set_state (*child, version);
1702 if ((child = find_named_node (node, "Script"))) {
1703 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1704 if (!(*n)->is_content ()) { continue; }
1706 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1708 Glib::Threads::Mutex::Lock lm (lua_lock);
1709 (*_lua_load)(std::string ((const char*)buf, size));
1710 } catch (luabridge::LuaException const& e) {
1711 cerr << "LuaException:" << e.what () << endl;
1717 if ((child = find_named_node (node, X_("Selection")))) {
1718 _selection->set_state (*child, version);
1721 update_route_record_state ();
1723 /* here beginneth the second phase ... */
1724 set_snapshot_name (_current_snapshot_name);
1726 StateReady (); /* EMIT SIGNAL */
1739 Session::load_routes (const XMLNode& node, int version)
1742 XMLNodeConstIterator niter;
1743 RouteList new_routes;
1745 nlist = node.children();
1749 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1751 boost::shared_ptr<Route> route;
1752 if (version < 3000) {
1753 route = XMLRouteFactory_2X (**niter, version);
1755 route = XMLRouteFactory (**niter, version);
1759 error << _("Session: cannot create Route from XML description.") << endmsg;
1763 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1765 new_routes.push_back (route);
1768 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1770 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1772 BootMessage (_("Finished adding tracks/busses"));
1777 boost::shared_ptr<Route>
1778 Session::XMLRouteFactory (const XMLNode& node, int version)
1780 boost::shared_ptr<Route> ret;
1782 if (node.name() != "Route") {
1786 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1788 DataType type = DataType::AUDIO;
1789 node.get_property("default-type", type);
1791 assert (type != DataType::NIL);
1795 boost::shared_ptr<Track> track;
1797 if (type == DataType::AUDIO) {
1798 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1800 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1803 if (track->init()) {
1807 if (track->set_state (node, version)) {
1811 BOOST_MARK_TRACK (track);
1815 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1816 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1818 if (r->init () == 0 && r->set_state (node, version) == 0) {
1819 BOOST_MARK_ROUTE (r);
1827 boost::shared_ptr<Route>
1828 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1830 boost::shared_ptr<Route> ret;
1832 if (node.name() != "Route") {
1836 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1838 ds_prop = node.property (X_("diskstream"));
1841 DataType type = DataType::AUDIO;
1842 node.get_property("default-type", type);
1844 assert (type != DataType::NIL);
1848 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1849 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1853 if (i == _diskstreams_2X.end()) {
1854 error << _("Could not find diskstream for route") << endmsg;
1855 return boost::shared_ptr<Route> ();
1858 boost::shared_ptr<Track> track;
1860 if (type == DataType::AUDIO) {
1861 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1863 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1866 if (track->init()) {
1870 if (track->set_state (node, version)) {
1874 track->set_diskstream (*i);
1876 BOOST_MARK_TRACK (track);
1880 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1881 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1883 if (r->init () == 0 && r->set_state (node, version) == 0) {
1884 BOOST_MARK_ROUTE (r);
1893 Session::load_regions (const XMLNode& node)
1896 XMLNodeConstIterator niter;
1897 boost::shared_ptr<Region> region;
1899 nlist = node.children();
1903 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1904 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1905 error << _("Session: cannot create Region from XML description.");
1906 XMLProperty const * name = (**niter).property("name");
1909 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1920 Session::load_compounds (const XMLNode& node)
1922 XMLNodeList calist = node.children();
1923 XMLNodeConstIterator caiter;
1924 XMLProperty const * caprop;
1926 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1927 XMLNode* ca = *caiter;
1931 if ((caprop = ca->property (X_("original"))) == 0) {
1934 orig_id = caprop->value();
1936 if ((caprop = ca->property (X_("copy"))) == 0) {
1939 copy_id = caprop->value();
1941 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1942 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1944 if (!orig || !copy) {
1945 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1951 RegionFactory::add_compound_association (orig, copy);
1958 Session::load_nested_sources (const XMLNode& node)
1961 XMLNodeConstIterator niter;
1963 nlist = node.children();
1965 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1966 if ((*niter)->name() == "Source") {
1968 /* it may already exist, so don't recreate it unnecessarily
1971 XMLProperty const * prop = (*niter)->property (X_("id"));
1973 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1977 ID source_id (prop->value());
1979 if (!source_by_id (source_id)) {
1982 SourceFactory::create (*this, **niter, true);
1984 catch (failed_constructor& err) {
1985 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1992 boost::shared_ptr<Region>
1993 Session::XMLRegionFactory (const XMLNode& node, bool full)
1995 XMLProperty const * type = node.property("type");
1999 const XMLNodeList& nlist = node.children();
2001 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2002 XMLNode *child = (*niter);
2003 if (child->name() == "NestedSource") {
2004 load_nested_sources (*child);
2008 if (!type || type->value() == "audio") {
2009 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2010 } else if (type->value() == "midi") {
2011 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2014 } catch (failed_constructor& err) {
2015 return boost::shared_ptr<Region> ();
2018 return boost::shared_ptr<Region> ();
2021 boost::shared_ptr<AudioRegion>
2022 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2024 XMLProperty const * prop;
2025 boost::shared_ptr<Source> source;
2026 boost::shared_ptr<AudioSource> as;
2028 SourceList master_sources;
2029 uint32_t nchans = 1;
2032 if (node.name() != X_("Region")) {
2033 return boost::shared_ptr<AudioRegion>();
2036 node.get_property (X_("channels"), nchans);
2038 if ((prop = node.property ("name")) == 0) {
2039 cerr << "no name for this region\n";
2043 if ((prop = node.property (X_("source-0"))) == 0) {
2044 if ((prop = node.property ("source")) == 0) {
2045 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2046 return boost::shared_ptr<AudioRegion>();
2050 PBD::ID s_id (prop->value());
2052 if ((source = source_by_id (s_id)) == 0) {
2053 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2054 return boost::shared_ptr<AudioRegion>();
2057 as = boost::dynamic_pointer_cast<AudioSource>(source);
2059 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2060 return boost::shared_ptr<AudioRegion>();
2063 sources.push_back (as);
2065 /* pickup other channels */
2067 for (uint32_t n=1; n < nchans; ++n) {
2068 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2069 if ((prop = node.property (buf)) != 0) {
2071 PBD::ID id2 (prop->value());
2073 if ((source = source_by_id (id2)) == 0) {
2074 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2075 return boost::shared_ptr<AudioRegion>();
2078 as = boost::dynamic_pointer_cast<AudioSource>(source);
2080 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2081 return boost::shared_ptr<AudioRegion>();
2083 sources.push_back (as);
2087 for (uint32_t n = 0; n < nchans; ++n) {
2088 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2089 if ((prop = node.property (buf)) != 0) {
2091 PBD::ID id2 (prop->value());
2093 if ((source = source_by_id (id2)) == 0) {
2094 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2095 return boost::shared_ptr<AudioRegion>();
2098 as = boost::dynamic_pointer_cast<AudioSource>(source);
2100 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2101 return boost::shared_ptr<AudioRegion>();
2103 master_sources.push_back (as);
2108 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2110 /* a final detail: this is the one and only place that we know how long missing files are */
2112 if (region->whole_file()) {
2113 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2114 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2116 sfp->set_length (region->length());
2121 if (!master_sources.empty()) {
2122 if (master_sources.size() != nchans) {
2123 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2125 region->set_master_sources (master_sources);
2133 catch (failed_constructor& err) {
2134 return boost::shared_ptr<AudioRegion>();
2138 boost::shared_ptr<MidiRegion>
2139 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2141 XMLProperty const * prop;
2142 boost::shared_ptr<Source> source;
2143 boost::shared_ptr<MidiSource> ms;
2146 if (node.name() != X_("Region")) {
2147 return boost::shared_ptr<MidiRegion>();
2150 if ((prop = node.property ("name")) == 0) {
2151 cerr << "no name for this region\n";
2155 if ((prop = node.property (X_("source-0"))) == 0) {
2156 if ((prop = node.property ("source")) == 0) {
2157 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2158 return boost::shared_ptr<MidiRegion>();
2162 PBD::ID s_id (prop->value());
2164 if ((source = source_by_id (s_id)) == 0) {
2165 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2166 return boost::shared_ptr<MidiRegion>();
2169 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2171 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2172 return boost::shared_ptr<MidiRegion>();
2175 sources.push_back (ms);
2178 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2179 /* a final detail: this is the one and only place that we know how long missing files are */
2181 if (region->whole_file()) {
2182 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2183 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2185 sfp->set_length (region->length());
2193 catch (failed_constructor& err) {
2194 return boost::shared_ptr<MidiRegion>();
2199 Session::get_sources_as_xml ()
2202 XMLNode* node = new XMLNode (X_("Sources"));
2203 Glib::Threads::Mutex::Lock lm (source_lock);
2205 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2206 node->add_child_nocopy (i->second->get_state());
2213 Session::reset_write_sources (bool mark_write_complete, bool force)
2215 boost::shared_ptr<RouteList> rl = routes.reader();
2216 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2217 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2219 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2220 tr->reset_write_sources(mark_write_complete, force);
2221 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2227 Session::load_sources (const XMLNode& node)
2230 XMLNodeConstIterator niter;
2231 /* don't need this but it stops some
2232 * versions of gcc complaining about
2233 * discarded return values.
2235 boost::shared_ptr<Source> source;
2237 nlist = node.children();
2240 std::map<std::string, std::string> relocation;
2242 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2243 #ifdef PLATFORM_WINDOWS
2247 XMLNode srcnode (**niter);
2248 bool try_replace_abspath = true;
2252 #ifdef PLATFORM_WINDOWS
2253 // do not show "insert media" popups (files embedded from removable media).
2254 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2256 if ((source = XMLSourceFactory (srcnode)) == 0) {
2257 error << _("Session: cannot create Source from XML description.") << endmsg;
2259 #ifdef PLATFORM_WINDOWS
2260 SetErrorMode(old_mode);
2263 } catch (MissingSource& err) {
2264 #ifdef PLATFORM_WINDOWS
2265 SetErrorMode(old_mode);
2268 /* try previous abs path replacements first */
2269 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2270 std::string dir = Glib::path_get_dirname (err.path);
2271 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2272 if (rl != relocation.end ()) {
2273 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2274 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2275 srcnode.set_property ("origin", newpath);
2276 try_replace_abspath = false;
2283 _missing_file_replacement = "";
2285 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2286 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2287 PROGRAM_NAME) << endmsg;
2291 if (!no_questions_about_missing_files) {
2292 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2297 switch (user_choice) {
2299 /* user added a new search location
2300 * or selected a new absolute path,
2302 if (Glib::path_is_absolute (err.path)) {
2303 if (!_missing_file_replacement.empty ()) {
2304 /* replace origin, in XML */
2305 std::string newpath = Glib::build_filename (
2306 _missing_file_replacement, Glib::path_get_basename (err.path));
2307 srcnode.set_property ("origin", newpath);
2308 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2309 _missing_file_replacement = "";
2316 /* user asked to quit the entire session load */
2320 no_questions_about_missing_files = true;
2324 no_questions_about_missing_files = true;
2331 case DataType::AUDIO:
2332 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2335 case DataType::MIDI:
2336 /* The MIDI file is actually missing so
2337 * just create a new one in the same
2338 * location. Do not announce its
2342 if (!Glib::path_is_absolute (err.path)) {
2343 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2345 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2350 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2351 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2352 /* reset ID to match the missing one */
2353 source->set_id (**niter);
2354 /* Now we can announce it */
2355 SourceFactory::SourceCreated (source);
2366 boost::shared_ptr<Source>
2367 Session::XMLSourceFactory (const XMLNode& node)
2369 if (node.name() != "Source") {
2370 return boost::shared_ptr<Source>();
2374 /* note: do peak building in another thread when loading session state */
2375 return SourceFactory::create (*this, node, true);
2378 catch (failed_constructor& err) {
2379 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2380 return boost::shared_ptr<Source>();
2385 Session::save_template (string template_name, bool replace_existing)
2387 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2391 bool absolute_path = Glib::path_is_absolute (template_name);
2393 /* directory to put the template in */
2394 std::string template_dir_path;
2396 if (!absolute_path) {
2397 std::string user_template_dir(user_template_directory());
2399 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2400 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2401 user_template_dir, g_strerror (errno)) << endmsg;
2405 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2407 template_dir_path = template_name;
2410 if (!ARDOUR::Profile->get_trx()) {
2411 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2412 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2413 template_dir_path) << endmsg;
2417 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2418 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2419 template_dir_path, g_strerror (errno)) << endmsg;
2425 std::string template_file_path;
2427 if (ARDOUR::Profile->get_trx()) {
2428 template_file_path = template_name;
2430 if (absolute_path) {
2431 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2433 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2437 SessionSaveUnderway (); /* EMIT SIGNAL */
2442 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2443 tree.set_root (&get_template());
2446 if (!tree.write (template_file_path)) {
2447 error << _("template not saved") << endmsg;
2451 store_recent_templates (template_file_path);
2457 Session::refresh_disk_space ()
2459 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2461 Glib::Threads::Mutex::Lock lm (space_lock);
2463 /* get freespace on every FS that is part of the session path */
2465 _total_free_4k_blocks = 0;
2466 _total_free_4k_blocks_uncertain = false;
2468 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2469 #if defined(__NetBSD__)
2470 struct statvfs statfsbuf;
2472 statvfs (i->path.c_str(), &statfsbuf);
2474 struct statfs statfsbuf;
2476 statfs (i->path.c_str(), &statfsbuf);
2478 double const scale = statfsbuf.f_bsize / 4096.0;
2480 /* See if this filesystem is read-only */
2481 struct statvfs statvfsbuf;
2482 statvfs (i->path.c_str(), &statvfsbuf);
2484 /* f_bavail can be 0 if it is undefined for whatever
2485 filesystem we are looking at; Samba shares mounted
2486 via GVFS are an example of this.
2488 if (statfsbuf.f_bavail == 0) {
2489 /* block count unknown */
2491 i->blocks_unknown = true;
2492 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2493 /* read-only filesystem */
2495 i->blocks_unknown = false;
2497 /* read/write filesystem with known space */
2498 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2499 i->blocks_unknown = false;
2502 _total_free_4k_blocks += i->blocks;
2503 if (i->blocks_unknown) {
2504 _total_free_4k_blocks_uncertain = true;
2507 #elif defined PLATFORM_WINDOWS
2508 vector<string> scanned_volumes;
2509 vector<string>::iterator j;
2510 vector<space_and_path>::iterator i;
2511 DWORD nSectorsPerCluster, nBytesPerSector,
2512 nFreeClusters, nTotalClusters;
2516 _total_free_4k_blocks = 0;
2518 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2519 strncpy (disk_drive, (*i).path.c_str(), 3);
2523 volume_found = false;
2524 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2526 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2527 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2528 i->blocks = (uint32_t)(nFreeBytes / 4096);
2530 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2531 if (0 == j->compare(disk_drive)) {
2532 volume_found = true;
2537 if (!volume_found) {
2538 scanned_volumes.push_back(disk_drive);
2539 _total_free_4k_blocks += i->blocks;
2544 if (0 == _total_free_4k_blocks) {
2545 strncpy (disk_drive, path().c_str(), 3);
2548 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2550 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2551 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2552 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2559 Session::get_best_session_directory_for_new_audio ()
2561 vector<space_and_path>::iterator i;
2562 string result = _session_dir->root_path();
2564 /* handle common case without system calls */
2566 if (session_dirs.size() == 1) {
2570 /* OK, here's the algorithm we're following here:
2572 We want to select which directory to use for
2573 the next file source to be created. Ideally,
2574 we'd like to use a round-robin process so as to
2575 get maximum performance benefits from splitting
2576 the files across multiple disks.
2578 However, in situations without much diskspace, an
2579 RR approach may end up filling up a filesystem
2580 with new files while others still have space.
2581 Its therefore important to pay some attention to
2582 the freespace in the filesystem holding each
2583 directory as well. However, if we did that by
2584 itself, we'd keep creating new files in the file
2585 system with the most space until it was as full
2586 as all others, thus negating any performance
2587 benefits of this RAID-1 like approach.
2589 So, we use a user-configurable space threshold. If
2590 there are at least 2 filesystems with more than this
2591 much space available, we use RR selection between them.
2592 If not, then we pick the filesystem with the most space.
2594 This gets a good balance between the two
2598 refresh_disk_space ();
2600 int free_enough = 0;
2602 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2603 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2608 if (free_enough >= 2) {
2609 /* use RR selection process, ensuring that the one
2613 i = last_rr_session_dir;
2616 if (++i == session_dirs.end()) {
2617 i = session_dirs.begin();
2620 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2621 SessionDirectory sdir(i->path);
2622 if (sdir.create ()) {
2624 last_rr_session_dir = i;
2629 } while (i != last_rr_session_dir);
2633 /* pick FS with the most freespace (and that
2634 seems to actually work ...)
2637 vector<space_and_path> sorted;
2638 space_and_path_ascending_cmp cmp;
2640 sorted = session_dirs;
2641 sort (sorted.begin(), sorted.end(), cmp);
2643 for (i = sorted.begin(); i != sorted.end(); ++i) {
2644 SessionDirectory sdir(i->path);
2645 if (sdir.create ()) {
2647 last_rr_session_dir = i;
2657 Session::automation_dir () const
2659 return Glib::build_filename (_path, automation_dir_name);
2663 Session::analysis_dir () const
2665 return Glib::build_filename (_path, analysis_dir_name);
2669 Session::plugins_dir () const
2671 return Glib::build_filename (_path, plugins_dir_name);
2675 Session::externals_dir () const
2677 return Glib::build_filename (_path, externals_dir_name);
2681 Session::load_bundles (XMLNode const & node)
2683 XMLNodeList nlist = node.children();
2684 XMLNodeConstIterator niter;
2688 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2689 if ((*niter)->name() == "InputBundle") {
2690 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2691 } else if ((*niter)->name() == "OutputBundle") {
2692 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2694 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2703 Session::load_route_groups (const XMLNode& node, int version)
2705 XMLNodeList nlist = node.children();
2706 XMLNodeConstIterator niter;
2710 if (version >= 3000) {
2712 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2713 if ((*niter)->name() == "RouteGroup") {
2714 RouteGroup* rg = new RouteGroup (*this, "");
2715 add_route_group (rg);
2716 rg->set_state (**niter, version);
2720 } else if (version < 3000) {
2722 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2723 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2724 RouteGroup* rg = new RouteGroup (*this, "");
2725 add_route_group (rg);
2726 rg->set_state (**niter, version);
2735 state_file_filter (const string &str, void* /*arg*/)
2737 return (str.length() > strlen(statefile_suffix) &&
2738 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2742 remove_end(string state)
2744 string statename(state);
2746 string::size_type start,end;
2747 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2748 statename = statename.substr (start+1);
2751 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2752 end = statename.length();
2755 return string(statename.substr (0, end));
2759 Session::possible_states (string path)
2761 vector<string> states;
2762 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2764 transform(states.begin(), states.end(), states.begin(), remove_end);
2766 sort (states.begin(), states.end());
2772 Session::possible_states () const
2774 return possible_states(_path);
2778 Session::new_route_group (const std::string& name)
2780 RouteGroup* rg = NULL;
2782 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2783 if ((*i)->name () == name) {
2790 rg = new RouteGroup (*this, name);
2791 add_route_group (rg);
2797 Session::add_route_group (RouteGroup* g)
2799 _route_groups.push_back (g);
2800 route_group_added (g); /* EMIT SIGNAL */
2802 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2803 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2804 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2810 Session::remove_route_group (RouteGroup& rg)
2812 list<RouteGroup*>::iterator i;
2814 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2815 _route_groups.erase (i);
2818 route_group_removed (); /* EMIT SIGNAL */
2822 /** Set a new order for our route groups, without adding or removing any.
2823 * @param groups Route group list in the new order.
2826 Session::reorder_route_groups (list<RouteGroup*> groups)
2828 _route_groups = groups;
2830 route_groups_reordered (); /* EMIT SIGNAL */
2836 Session::route_group_by_name (string name)
2838 list<RouteGroup *>::iterator i;
2840 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2841 if ((*i)->name() == name) {
2849 Session::all_route_group() const
2851 return *_all_route_group;
2855 Session::add_commands (vector<Command*> const & cmds)
2857 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2863 Session::add_command (Command* const cmd)
2865 assert (_current_trans);
2866 DEBUG_UNDO_HISTORY (
2867 string_compose ("Current Undo Transaction %1, adding command: %2",
2868 _current_trans->name (),
2870 _current_trans->add_command (cmd);
2873 PBD::StatefulDiffCommand*
2874 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2876 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2882 Session::begin_reversible_command (const string& name)
2884 begin_reversible_command (g_quark_from_string (name.c_str ()));
2887 /** Begin a reversible command using a GQuark to identify it.
2888 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2889 * but there must be as many begin...()s as there are commit...()s.
2892 Session::begin_reversible_command (GQuark q)
2894 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2895 to hold all the commands that are committed. This keeps the order of
2896 commands correct in the history.
2899 if (_current_trans == 0) {
2900 DEBUG_UNDO_HISTORY (string_compose (
2901 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2903 /* start a new transaction */
2904 assert (_current_trans_quarks.empty ());
2905 _current_trans = new UndoTransaction();
2906 _current_trans->set_name (g_quark_to_string (q));
2908 DEBUG_UNDO_HISTORY (
2909 string_compose ("Begin Reversible Command, current transaction: %1",
2910 _current_trans->name ()));
2913 _current_trans_quarks.push_front (q);
2917 Session::abort_reversible_command ()
2919 if (_current_trans != 0) {
2920 DEBUG_UNDO_HISTORY (
2921 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2922 _current_trans->clear();
2923 delete _current_trans;
2925 _current_trans_quarks.clear();
2930 Session::commit_reversible_command (Command *cmd)
2932 assert (_current_trans);
2933 assert (!_current_trans_quarks.empty ());
2938 DEBUG_UNDO_HISTORY (
2939 string_compose ("Current Undo Transaction %1, adding command: %2",
2940 _current_trans->name (),
2942 _current_trans->add_command (cmd);
2945 DEBUG_UNDO_HISTORY (
2946 string_compose ("Commit Reversible Command, current transaction: %1",
2947 _current_trans->name ()));
2949 _current_trans_quarks.pop_front ();
2951 if (!_current_trans_quarks.empty ()) {
2952 DEBUG_UNDO_HISTORY (
2953 string_compose ("Commit Reversible Command, transaction is not "
2954 "top-level, current transaction: %1",
2955 _current_trans->name ()));
2956 /* the transaction we're committing is not the top-level one */
2960 if (_current_trans->empty()) {
2961 /* no commands were added to the transaction, so just get rid of it */
2962 DEBUG_UNDO_HISTORY (
2963 string_compose ("Commit Reversible Command, No commands were "
2964 "added to current transaction: %1",
2965 _current_trans->name ()));
2966 delete _current_trans;
2971 gettimeofday (&now, 0);
2972 _current_trans->set_timestamp (now);
2974 _history.add (_current_trans);
2979 accept_all_audio_files (const string& path, void* /*arg*/)
2981 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2985 if (!AudioFileSource::safe_audio_file_extension (path)) {
2993 accept_all_midi_files (const string& path, void* /*arg*/)
2995 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2999 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3000 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3001 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3005 accept_all_state_files (const string& path, void* /*arg*/)
3007 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3011 std::string const statefile_ext (statefile_suffix);
3012 if (path.length() >= statefile_ext.length()) {
3013 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3020 Session::find_all_sources (string path, set<string>& result)
3025 if (!tree.read (path)) {
3029 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3034 XMLNodeConstIterator niter;
3036 nlist = node->children();
3040 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3042 XMLProperty const * prop;
3044 if ((prop = (*niter)->property (X_("type"))) == 0) {
3048 DataType type (prop->value());
3050 if ((prop = (*niter)->property (X_("name"))) == 0) {
3054 if (Glib::path_is_absolute (prop->value())) {
3055 /* external file, ignore */
3063 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3064 result.insert (found_path);
3072 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3074 vector<string> state_files;
3076 string this_snapshot_path;
3082 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3083 ripped = ripped.substr (0, ripped.length() - 1);
3086 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3088 if (state_files.empty()) {
3093 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3094 this_snapshot_path += statefile_suffix;
3096 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3098 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3100 if (exclude_this_snapshot && *i == this_snapshot_path) {
3101 cerr << "\texcluded\n";
3106 if (find_all_sources (*i, result) < 0) {
3114 struct RegionCounter {
3115 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3116 AudioSourceList::iterator iter;
3117 boost::shared_ptr<Region> region;
3120 RegionCounter() : count (0) {}
3124 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3126 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3127 return r.get_value_or (1);
3131 Session::cleanup_regions ()
3133 bool removed = false;
3134 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3136 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3138 uint32_t used = playlists->region_use_count (i->second);
3140 if (used == 0 && !i->second->automatic ()) {
3141 boost::weak_ptr<Region> w = i->second;
3144 RegionFactory::map_remove (w);
3151 // re-check to remove parent references of compound regions
3152 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3153 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3157 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3158 if (0 == playlists->region_use_count (i->second)) {
3159 boost::weak_ptr<Region> w = i->second;
3161 RegionFactory::map_remove (w);
3168 /* dump the history list */
3175 Session::can_cleanup_peakfiles () const
3177 if (deletion_in_progress()) {
3180 if (!_writable || (_state_of_the_state & CannotSave)) {
3181 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3184 if (record_status() == Recording) {
3185 error << _("Cannot cleanup peak-files while recording") << endmsg;
3192 Session::cleanup_peakfiles ()
3194 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3199 assert (can_cleanup_peakfiles ());
3200 assert (!peaks_cleanup_in_progres());
3202 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3204 int timeout = 5000; // 5 seconds
3205 while (!SourceFactory::files_with_peaks.empty()) {
3206 Glib::usleep (1000);
3207 if (--timeout < 0) {
3208 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3209 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3214 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3215 boost::shared_ptr<AudioSource> as;
3216 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3217 as->close_peakfile();
3221 PBD::clear_directory (session_directory().peak_path());
3223 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3225 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3226 boost::shared_ptr<AudioSource> as;
3227 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3228 SourceFactory::setup_peakfile(as, true);
3235 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3237 pl->deep_sources (*all_sources);
3241 Session::cleanup_sources (CleanupReport& rep)
3243 // FIXME: needs adaptation to midi
3245 vector<boost::shared_ptr<Source> > dead_sources;
3248 vector<string> candidates;
3249 vector<string> unused;
3250 set<string> sources_used_by_all_snapshots;
3257 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3259 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3261 /* this is mostly for windows which doesn't allow file
3262 * renaming if the file is in use. But we don't special
3263 * case it because we need to know if this causes
3264 * problems, and the easiest way to notice that is to
3265 * keep it in place for all platforms.
3268 request_stop (false);
3270 _butler->wait_until_finished ();
3272 /* consider deleting all unused playlists */
3274 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3279 /* sync the "all regions" property of each playlist with its current state */
3281 playlists->sync_all_regions_with_regions ();
3283 /* find all un-used sources */
3288 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3290 SourceMap::iterator tmp;
3295 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3299 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3300 dead_sources.push_back (i->second);
3301 i->second->drop_references ();
3307 /* build a list of all the possible audio directories for the session */
3309 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3310 SessionDirectory sdir ((*i).path);
3311 asp += sdir.sound_path();
3313 audio_path += asp.to_string();
3316 /* build a list of all the possible midi directories for the session */
3318 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3319 SessionDirectory sdir ((*i).path);
3320 msp += sdir.midi_path();
3322 midi_path += msp.to_string();
3324 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3325 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3327 /* add sources from all other snapshots as "used", but don't use this
3328 snapshot because the state file on disk still references sources we
3329 may have already dropped.
3332 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3334 /* Although the region factory has a list of all regions ever created
3335 * for this session, we're only interested in regions actually in
3336 * playlists right now. So merge all playlist regions lists together.
3338 * This will include the playlists used within compound regions.
3341 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3343 /* add our current source list
3346 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3347 boost::shared_ptr<FileSource> fs;
3348 SourceMap::iterator tmp = i;
3351 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3357 /* this is mostly for windows which doesn't allow file
3358 * renaming if the file is in use. But we do not special
3359 * case it because we need to know if this causes
3360 * problems, and the easiest way to notice that is to
3361 * keep it in place for all platforms.
3366 if (!fs->is_stub()) {
3368 /* Note that we're checking a list of all
3369 * sources across all snapshots with the list
3370 * of sources used by this snapshot.
3373 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3374 /* this source is in use by this snapshot */
3375 sources_used_by_all_snapshots.insert (fs->path());
3376 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3378 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3379 /* this source is NOT in use by this snapshot */
3381 /* remove all related regions from RegionFactory master list */
3383 RegionFactory::remove_regions_using_source (i->second);
3385 /* remove from our current source list
3386 * also. We may not remove it from
3387 * disk, because it may be used by
3388 * other snapshots, but it isn't used inside this
3389 * snapshot anymore, so we don't need a
3400 /* now check each candidate source to see if it exists in the list of
3401 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3404 cerr << "Candidates: " << candidates.size() << endl;
3405 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3407 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3412 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3414 tmppath1 = canonical_path (spath);
3415 tmppath2 = canonical_path ((*i));
3417 cerr << "\t => " << tmppath2 << endl;
3419 if (tmppath1 == tmppath2) {
3426 unused.push_back (spath);
3430 cerr << "Actually unused: " << unused.size() << endl;
3432 if (unused.empty()) {
3438 /* now try to move all unused files into the "dead" directory(ies) */
3440 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3445 /* don't move the file across filesystems, just
3446 * stick it in the `dead_dir_name' directory
3447 * on whichever filesystem it was already on.
3450 if ((*x).find ("/sounds/") != string::npos) {
3452 /* old school, go up 1 level */
3454 newpath = Glib::path_get_dirname (*x); // "sounds"
3455 newpath = Glib::path_get_dirname (newpath); // "session-name"
3459 /* new school, go up 4 levels */
3461 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3462 newpath = Glib::path_get_dirname (newpath); // "session-name"
3463 newpath = Glib::path_get_dirname (newpath); // "interchange"
3464 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3467 newpath = Glib::build_filename (newpath, dead_dir_name);
3469 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3470 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3474 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3476 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3478 /* the new path already exists, try versioning */
3480 char buf[PATH_MAX+1];
3484 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3487 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3488 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3492 if (version == 999) {
3493 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3497 newpath = newpath_v;
3502 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3503 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3504 newpath, g_strerror (errno)) << endmsg;
3508 /* see if there an easy to find peakfile for this file, and remove it. */
3510 string base = Glib::path_get_basename (*x);
3511 base += "%A"; /* this is what we add for the channel suffix of all native files,
3512 * or for the first channel of embedded files. it will miss
3513 * some peakfiles for other channels
3515 string peakpath = construct_peak_filepath (base);
3517 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3518 if (::g_unlink (peakpath.c_str ()) != 0) {
3519 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3520 g_strerror (errno)) << endmsg;
3521 /* try to back out */
3522 ::g_rename (newpath.c_str (), _path.c_str ());
3527 rep.paths.push_back (*x);
3528 rep.space += statbuf.st_size;
3531 /* dump the history list */
3535 /* save state so we don't end up a session file
3536 * referring to non-existent sources.
3543 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3549 Session::cleanup_trash_sources (CleanupReport& rep)
3551 // FIXME: needs adaptation for MIDI
3553 vector<space_and_path>::iterator i;
3559 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3561 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3563 clear_directory (dead_dir, &rep.space, &rep.paths);
3570 Session::set_dirty ()
3572 /* return early if there's nothing to do */
3577 /* never mark session dirty during loading */
3578 if (_state_of_the_state & Loading) {
3582 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3583 DirtyChanged(); /* EMIT SIGNAL */
3587 Session::set_clean ()
3589 bool was_dirty = dirty();
3591 _state_of_the_state = Clean;
3594 DirtyChanged(); /* EMIT SIGNAL */
3599 Session::set_deletion_in_progress ()
3601 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3605 Session::clear_deletion_in_progress ()
3607 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3611 Session::add_controllable (boost::shared_ptr<Controllable> c)
3613 /* this adds a controllable to the list managed by the Session.
3614 this is a subset of those managed by the Controllable class
3615 itself, and represents the only ones whose state will be saved
3616 as part of the session.
3619 Glib::Threads::Mutex::Lock lm (controllables_lock);
3620 controllables.insert (c);
3623 struct null_deleter { void operator()(void const *) const {} };
3626 Session::remove_controllable (Controllable* c)
3628 if (_state_of_the_state & Deletion) {
3632 Glib::Threads::Mutex::Lock lm (controllables_lock);
3634 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3636 if (x != controllables.end()) {
3637 controllables.erase (x);
3641 boost::shared_ptr<Controllable>
3642 Session::controllable_by_id (const PBD::ID& id)
3644 Glib::Threads::Mutex::Lock lm (controllables_lock);
3646 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3647 if ((*i)->id() == id) {
3652 return boost::shared_ptr<Controllable>();
3655 boost::shared_ptr<AutomationControl>
3656 Session::automation_control_by_id (const PBD::ID& id)
3658 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3661 boost::shared_ptr<Controllable>
3662 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3664 boost::shared_ptr<Controllable> c;
3665 boost::shared_ptr<Stripable> s;
3666 boost::shared_ptr<Route> r;
3668 switch (desc.top_level_type()) {
3669 case ControllableDescriptor::NamedRoute:
3671 std::string str = desc.top_level_name();
3673 if (str == "Master" || str == "master") {
3675 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3677 } else if (str == "auditioner") {
3680 s = route_by_name (desc.top_level_name());
3686 case ControllableDescriptor::PresentationOrderRoute:
3687 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3690 case ControllableDescriptor::PresentationOrderTrack:
3691 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3694 case ControllableDescriptor::PresentationOrderBus:
3695 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3698 case ControllableDescriptor::PresentationOrderVCA:
3699 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3702 case ControllableDescriptor::SelectionCount:
3703 s = route_by_selected_count (desc.selection_id());
3711 r = boost::dynamic_pointer_cast<Route> (s);
3713 switch (desc.subtype()) {
3714 case ControllableDescriptor::Gain:
3715 c = s->gain_control ();
3718 case ControllableDescriptor::Trim:
3719 c = s->trim_control ();
3722 case ControllableDescriptor::Solo:
3723 c = s->solo_control();
3726 case ControllableDescriptor::Mute:
3727 c = s->mute_control();
3730 case ControllableDescriptor::Recenable:
3731 c = s->rec_enable_control ();
3734 case ControllableDescriptor::PanDirection:
3735 c = s->pan_azimuth_control();
3738 case ControllableDescriptor::PanWidth:
3739 c = s->pan_width_control();
3742 case ControllableDescriptor::PanElevation:
3743 c = s->pan_elevation_control();
3746 case ControllableDescriptor::Balance:
3747 /* XXX simple pan control */
3750 case ControllableDescriptor::PluginParameter:
3752 uint32_t plugin = desc.target (0);
3753 uint32_t parameter_index = desc.target (1);
3755 /* revert to zero based counting */
3761 if (parameter_index > 0) {
3769 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3772 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3773 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3778 case ControllableDescriptor::SendGain: {
3779 uint32_t send = desc.target (0);
3786 c = r->send_level_controllable (send);
3791 /* relax and return a null pointer */
3799 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3802 Stateful::add_instant_xml (node, _path);
3805 if (write_to_config) {
3806 Config->add_instant_xml (node);
3811 Session::instant_xml (const string& node_name)
3813 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3814 if (get_disable_all_loaded_plugins ()) {
3818 return Stateful::instant_xml (node_name, _path);
3822 Session::save_history (string snapshot_name)
3830 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3831 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3835 if (snapshot_name.empty()) {
3836 snapshot_name = _current_snapshot_name;
3839 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3840 const string backup_filename = history_filename + backup_suffix;
3841 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3842 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3844 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3845 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3846 error << _("could not backup old history file, current history not saved") << endmsg;
3851 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3853 if (!tree.write (xml_path))
3855 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3857 if (g_remove (xml_path.c_str()) != 0) {
3858 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3859 xml_path, g_strerror (errno)) << endmsg;
3861 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3862 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3863 backup_path, g_strerror (errno)) << endmsg;
3873 Session::restore_history (string snapshot_name)
3877 if (snapshot_name.empty()) {
3878 snapshot_name = _current_snapshot_name;
3881 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3882 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3884 info << "Loading history from " << xml_path << endmsg;
3886 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3887 info << string_compose (_("%1: no history file \"%2\" for this session."),
3888 _name, xml_path) << endmsg;
3892 if (!tree.read (xml_path)) {
3893 error << string_compose (_("Could not understand session history file \"%1\""),
3894 xml_path) << endmsg;
3901 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3904 UndoTransaction* ut = new UndoTransaction ();
3910 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3911 !t->get_property ("tv-usec", tv_usec)) {
3915 ut->set_name (name);
3919 tv.tv_usec = tv_usec;
3920 ut->set_timestamp(tv);
3922 for (XMLNodeConstIterator child_it = t->children().begin();
3923 child_it != t->children().end(); child_it++)
3925 XMLNode *n = *child_it;
3928 if (n->name() == "MementoCommand" ||
3929 n->name() == "MementoUndoCommand" ||
3930 n->name() == "MementoRedoCommand") {
3932 if ((c = memento_command_factory(n))) {
3936 } else if (n->name() == "NoteDiffCommand") {
3937 PBD::ID id (n->property("midi-source")->value());
3938 boost::shared_ptr<MidiSource> midi_source =
3939 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3941 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3943 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3946 } else if (n->name() == "SysExDiffCommand") {
3948 PBD::ID id (n->property("midi-source")->value());
3949 boost::shared_ptr<MidiSource> midi_source =
3950 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3952 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3954 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3957 } else if (n->name() == "PatchChangeDiffCommand") {
3959 PBD::ID id (n->property("midi-source")->value());
3960 boost::shared_ptr<MidiSource> midi_source =
3961 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3963 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3965 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3968 } else if (n->name() == "StatefulDiffCommand") {
3969 if ((c = stateful_diff_command_factory (n))) {
3970 ut->add_command (c);
3973 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3984 Session::config_changed (std::string p, bool ours)
3990 if (p == "seamless-loop") {
3992 } else if (p == "rf-speed") {
3994 } else if (p == "auto-loop") {
3996 } else if (p == "session-monitoring") {
3998 } else if (p == "auto-input") {
4000 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4001 /* auto-input only makes a difference if we're rolling */
4002 set_track_monitor_input_status (!config.get_auto_input());
4005 } else if (p == "punch-in") {
4009 if ((location = _locations->auto_punch_location()) != 0) {
4011 if (config.get_punch_in ()) {
4012 replace_event (SessionEvent::PunchIn, location->start());
4014 remove_event (location->start(), SessionEvent::PunchIn);
4018 } else if (p == "punch-out") {
4022 if ((location = _locations->auto_punch_location()) != 0) {
4024 if (config.get_punch_out()) {
4025 replace_event (SessionEvent::PunchOut, location->end());
4027 clear_events (SessionEvent::PunchOut);
4031 } else if (p == "edit-mode") {
4033 Glib::Threads::Mutex::Lock lm (playlists->lock);
4035 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4036 (*i)->set_edit_mode (Config->get_edit_mode ());
4039 } else if (p == "use-video-sync") {
4041 waiting_for_sync_offset = config.get_use_video_sync();
4043 } else if (p == "mmc-control") {
4045 //poke_midi_thread ();
4047 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4049 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4051 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4053 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4055 } else if (p == "midi-control") {
4057 //poke_midi_thread ();
4059 } else if (p == "raid-path") {
4061 setup_raid_path (config.get_raid_path());
4063 } else if (p == "timecode-format") {
4067 } else if (p == "video-pullup") {
4071 } else if (p == "seamless-loop") {
4073 if (play_loop && transport_rolling()) {
4074 // to reset diskstreams etc
4075 request_play_loop (true);
4078 } else if (p == "rf-speed") {
4080 cumulative_rf_motion = 0;
4083 } else if (p == "click-sound") {
4085 setup_click_sounds (1);
4087 } else if (p == "click-emphasis-sound") {
4089 setup_click_sounds (-1);
4091 } else if (p == "clicking") {
4093 if (Config->get_clicking()) {
4094 if (_click_io && click_data) { // don't require emphasis data
4101 } else if (p == "click-record-only") {
4103 _click_rec_only = Config->get_click_record_only();
4105 } else if (p == "click-gain") {
4108 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4111 } else if (p == "send-mtc") {
4113 if (Config->get_send_mtc ()) {
4114 /* mark us ready to send */
4115 next_quarter_frame_to_send = 0;
4118 } else if (p == "send-mmc") {
4120 _mmc->enable_send (Config->get_send_mmc ());
4122 } else if (p == "jack-time-master") {
4124 engine().reset_timebase ();
4126 } else if (p == "native-file-header-format") {
4128 if (!first_file_header_format_reset) {
4129 reset_native_file_format ();
4132 first_file_header_format_reset = false;
4134 } else if (p == "native-file-data-format") {
4136 if (!first_file_data_format_reset) {
4137 reset_native_file_format ();
4140 first_file_data_format_reset = false;
4142 } else if (p == "external-sync") {
4143 if (!config.get_external_sync()) {
4144 drop_sync_source ();
4146 switch_to_sync_source (Config->get_sync_source());
4148 } else if (p == "denormal-model") {
4150 } else if (p == "history-depth") {
4151 set_history_depth (Config->get_history_depth());
4152 } else if (p == "remote-model") {
4153 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4156 } else if (p == "initial-program-change") {
4158 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4161 buf[0] = MIDI::program; // channel zero by default
4162 buf[1] = (Config->get_initial_program_change() & 0x7f);
4164 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4166 } else if (p == "solo-mute-override") {
4167 // catch_up_on_solo_mute_override ();
4168 } else if (p == "listen-position" || p == "pfl-position") {
4169 listen_position_changed ();
4170 } else if (p == "solo-control-is-listen-control") {
4171 solo_control_mode_changed ();
4172 } else if (p == "solo-mute-gain") {
4173 _solo_cut_control->Changed (true, Controllable::NoGroup);
4174 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4175 last_timecode_valid = false;
4176 } else if (p == "playback-buffer-seconds") {
4177 AudioSource::allocate_working_buffers (frame_rate());
4178 } else if (p == "ltc-source-port") {
4179 reconnect_ltc_input ();
4180 } else if (p == "ltc-sink-port") {
4181 reconnect_ltc_output ();
4182 } else if (p == "timecode-generator-offset") {
4183 ltc_tx_parse_offset();
4184 } else if (p == "auto-return-target-list") {
4185 follow_playhead_priority ();
4192 Session::set_history_depth (uint32_t d)
4194 _history.set_depth (d);
4198 Session::load_diskstreams_2X (XMLNode const & node, int)
4201 XMLNodeConstIterator citer;
4203 clist = node.children();
4205 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4208 /* diskstreams added automatically by DiskstreamCreated handler */
4209 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4210 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4211 _diskstreams_2X.push_back (dsp);
4213 error << _("Session: unknown diskstream type in XML") << endmsg;
4217 catch (failed_constructor& err) {
4218 error << _("Session: could not load diskstream via XML state") << endmsg;
4226 /** Connect things to the MMC object */
4228 Session::setup_midi_machine_control ()
4230 _mmc = new MIDI::MachineControl;
4232 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4233 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4235 if (!async_out || !async_out) {
4239 /* XXXX argh, passing raw pointers back into libmidi++ */
4241 MIDI::Port* mmc_in = async_in.get();
4242 MIDI::Port* mmc_out = async_out.get();
4244 _mmc->set_ports (mmc_in, mmc_out);
4246 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4247 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4248 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4249 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4250 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4251 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4252 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4253 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4254 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4255 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4256 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4257 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4258 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4260 /* also handle MIDI SPP because its so common */
4262 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4263 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4264 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4267 boost::shared_ptr<Controllable>
4268 Session::solo_cut_control() const
4270 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4271 * controls in Ardour that currently get presented to the user in the GUI that require
4272 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4274 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4275 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4278 return _solo_cut_control;
4282 Session::save_snapshot_name (const std::string & n)
4284 /* assure Stateful::_instant_xml is loaded
4285 * add_instant_xml() only adds to existing data and defaults
4286 * to use an empty Tree otherwise
4288 instant_xml ("LastUsedSnapshot");
4290 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4291 last_used_snapshot->set_property ("name", n);
4292 add_instant_xml (*last_used_snapshot, false);
4296 Session::set_snapshot_name (const std::string & n)
4298 _current_snapshot_name = n;
4299 save_snapshot_name (n);
4303 Session::rename (const std::string& new_name)
4305 string legal_name = legalize_for_path (new_name);
4311 string const old_sources_root = _session_dir->sources_root();
4313 if (!_writable || (_state_of_the_state & CannotSave)) {
4314 error << _("Cannot rename read-only session.") << endmsg;
4315 return 0; // don't show "messed up" warning
4317 if (record_status() == Recording) {
4318 error << _("Cannot rename session while recording") << endmsg;
4319 return 0; // don't show "messed up" warning
4322 StateProtector stp (this);
4327 * interchange subdirectory
4331 * Backup files are left unchanged and not renamed.
4334 /* Windows requires that we close all files before attempting the
4335 * rename. This works on other platforms, but isn't necessary there.
4336 * Leave it in place for all platforms though, since it may help
4337 * catch issues that could arise if the way Source files work ever
4338 * change (since most developers are not using Windows).
4341 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4342 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4348 /* pass one: not 100% safe check that the new directory names don't
4352 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4356 /* this is a stupid hack because Glib::path_get_dirname() is
4357 * lexical-only, and so passing it /a/b/c/ gives a different
4358 * result than passing it /a/b/c ...
4361 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4362 oldstr = oldstr.substr (0, oldstr.length() - 1);
4365 string base = Glib::path_get_dirname (oldstr);
4367 newstr = Glib::build_filename (base, legal_name);
4369 cerr << "Looking for " << newstr << endl;
4371 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4372 cerr << " exists\n";
4381 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4387 /* this is a stupid hack because Glib::path_get_dirname() is
4388 * lexical-only, and so passing it /a/b/c/ gives a different
4389 * result than passing it /a/b/c ...
4392 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4393 oldstr = oldstr.substr (0, oldstr.length() - 1);
4396 string base = Glib::path_get_dirname (oldstr);
4397 newstr = Glib::build_filename (base, legal_name);
4399 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4401 cerr << "Rename " << oldstr << " => " << newstr << endl;
4402 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4403 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4404 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4408 /* Reset path in "session dirs" */
4413 /* reset primary SessionDirectory object */
4416 (*_session_dir) = newstr;
4421 /* now rename directory below session_dir/interchange */
4423 string old_interchange_dir;
4424 string new_interchange_dir;
4426 /* use newstr here because we renamed the path
4427 * (folder/directory) that used to be oldstr to newstr above
4430 v.push_back (newstr);
4431 v.push_back (interchange_dir_name);
4432 v.push_back (Glib::path_get_basename (oldstr));
4434 old_interchange_dir = Glib::build_filename (v);
4437 v.push_back (newstr);
4438 v.push_back (interchange_dir_name);
4439 v.push_back (legal_name);
4441 new_interchange_dir = Glib::build_filename (v);
4443 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4445 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4446 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4447 old_interchange_dir, new_interchange_dir,
4450 error << string_compose (_("renaming %s as %2 failed (%3)"),
4451 old_interchange_dir, new_interchange_dir,
4460 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4461 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4463 cerr << "Rename " << oldstr << " => " << newstr << endl;
4465 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4466 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4467 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4473 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4475 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4476 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4478 cerr << "Rename " << oldstr << " => " << newstr << endl;
4480 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4481 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4482 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4487 /* remove old name from recent sessions */
4488 remove_recent_sessions (_path);
4491 /* update file source paths */
4493 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4494 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4496 string p = fs->path ();
4497 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4499 SourceFactory::setup_peakfile(i->second, true);
4503 set_snapshot_name (new_name);
4508 /* save state again to get everything just right */
4510 save_state (_current_snapshot_name);
4512 /* add to recent sessions */
4514 store_recent_sessions (new_name, _path);
4520 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4522 bool found_sr = false;
4523 bool found_data_format = false;
4524 program_version = "";
4526 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4530 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4534 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4537 xmlFreeParserCtxt(ctxt);
4541 xmlNodePtr node = xmlDocGetRootElement(doc);
4544 xmlFreeParserCtxt(ctxt);
4552 for (attr = node->properties; attr; attr = attr->next) {
4553 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4554 sample_rate = atoi ((char*)attr->children->content);
4559 node = node->children;
4560 while (node != NULL) {
4561 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4562 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4564 program_version = string ((const char*)val);
4565 size_t sep = program_version.find_first_of("-");
4566 if (sep != string::npos) {
4567 program_version = program_version.substr (0, sep);
4572 if (strcmp((const char*) node->name, "Config")) {
4576 for (node = node->children; node; node = node->next) {
4577 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4578 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4580 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4582 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4584 found_data_format = true;
4594 xmlFreeParserCtxt(ctxt);
4597 return !(found_sr && found_data_format); // zero if they are both found
4601 Session::get_snapshot_from_instant (const std::string& session_dir)
4603 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4605 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4610 if (!tree.read (instant_xml_path)) {
4614 XMLProperty const * prop;
4615 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4616 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4617 return prop->value();
4623 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4624 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4627 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4631 SourcePathMap source_path_map;
4633 boost::shared_ptr<AudioFileSource> afs;
4638 Glib::Threads::Mutex::Lock lm (source_lock);
4640 cerr << " total sources = " << sources.size();
4642 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4643 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4649 if (fs->within_session()) {
4653 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4654 source_path_map[fs->path()].push_back (fs);
4656 SeveralFileSources v;
4658 source_path_map.insert (make_pair (fs->path(), v));
4664 cerr << " fsources = " << total << endl;
4666 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4668 /* tell caller where we are */
4670 string old_path = i->first;
4672 callback (n, total, old_path);
4674 cerr << old_path << endl;
4678 switch (i->second.front()->type()) {
4679 case DataType::AUDIO:
4680 new_path = new_audio_source_path_for_embedded (old_path);
4683 case DataType::MIDI:
4684 /* XXX not implemented yet */
4688 if (new_path.empty()) {
4692 cerr << "Move " << old_path << " => " << new_path << endl;
4694 if (!copy_file (old_path, new_path)) {
4695 cerr << "failed !\n";
4699 /* make sure we stop looking in the external
4700 dir/folder. Remember, this is an all-or-nothing
4701 operations, it doesn't merge just some files.
4703 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4705 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4706 (*f)->set_path (new_path);
4711 save_state ("", false, false);
4717 bool accept_all_files (string const &, void *)
4723 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4725 /* 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.
4730 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4732 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4734 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4736 v.push_back (new_session_folder); /* full path */
4737 v.push_back (interchange_dir_name);
4738 v.push_back (new_session_path); /* just one directory/folder */
4739 v.push_back (typedir);
4740 v.push_back (Glib::path_get_basename (old_path));
4742 return Glib::build_filename (v);
4746 Session::save_as (SaveAs& saveas)
4748 vector<string> files;
4749 string current_folder = Glib::path_get_dirname (_path);
4750 string new_folder = legalize_for_path (saveas.new_name);
4751 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4752 int64_t total_bytes = 0;
4756 int32_t internal_file_cnt = 0;
4758 vector<string> do_not_copy_extensions;
4759 do_not_copy_extensions.push_back (statefile_suffix);
4760 do_not_copy_extensions.push_back (pending_suffix);
4761 do_not_copy_extensions.push_back (backup_suffix);
4762 do_not_copy_extensions.push_back (temp_suffix);
4763 do_not_copy_extensions.push_back (history_suffix);
4765 /* get total size */
4767 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4769 /* need to clear this because
4770 * find_files_matching_filter() is cumulative
4775 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4777 all += files.size();
4779 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4781 g_stat ((*i).c_str(), &gsb);
4782 total_bytes += gsb.st_size;
4786 /* save old values so we can switch back if we are not switching to the new session */
4788 string old_path = _path;
4789 string old_name = _name;
4790 string old_snapshot = _current_snapshot_name;
4791 string old_sd = _session_dir->root_path();
4792 vector<string> old_search_path[DataType::num_types];
4793 string old_config_search_path[DataType::num_types];
4795 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4796 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4797 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4798 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4800 /* switch session directory */
4802 (*_session_dir) = to_dir;
4804 /* create new tree */
4806 if (!_session_dir->create()) {
4807 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4812 /* copy all relevant files. Find each location in session_dirs,
4813 * and copy files from there to target.
4816 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4818 /* need to clear this because
4819 * find_files_matching_filter() is cumulative
4824 const size_t prefix_len = (*sd).path.size();
4826 /* Work just on the files within this session dir */
4828 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4830 /* add dir separator to protect against collisions with
4831 * track names (e.g. track named "audiofiles" or
4835 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4836 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4837 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4839 /* copy all the files. Handling is different for media files
4840 than others because of the *silly* subtree we have below the interchange
4841 folder. That really was a bad idea, but I'm not fixing it as part of
4842 implementing ::save_as().
4845 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4847 std::string from = *i;
4850 string filename = Glib::path_get_basename (from);
4851 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4852 if (filename == ".DS_STORE") {
4857 if (from.find (audiofile_dir_string) != string::npos) {
4859 /* audio file: only copy if asked */
4861 if (saveas.include_media && saveas.copy_media) {
4863 string to = make_new_media_path (*i, to_dir, new_folder);
4865 info << "media file copying from " << from << " to " << to << endmsg;
4867 if (!copy_file (from, to)) {
4868 throw Glib::FileError (Glib::FileError::IO_ERROR,
4869 string_compose(_("\ncopying \"%1\" failed !"), from));
4873 /* we found media files inside the session folder */
4875 internal_file_cnt++;
4877 } else if (from.find (midifile_dir_string) != string::npos) {
4879 /* midi file: always copy unless
4880 * creating an empty new session
4883 if (saveas.include_media) {
4885 string to = make_new_media_path (*i, to_dir, new_folder);
4887 info << "media file copying from " << from << " to " << to << endmsg;
4889 if (!copy_file (from, to)) {
4890 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4894 /* we found media files inside the session folder */
4896 internal_file_cnt++;
4898 } else if (from.find (analysis_dir_string) != string::npos) {
4900 /* make sure analysis dir exists in
4901 * new session folder, but we're not
4902 * copying analysis files here, see
4906 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4911 /* normal non-media file. Don't copy state, history, etc.
4914 bool do_copy = true;
4916 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4917 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4918 /* end of filename matches extension, do not copy file */
4924 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4925 /* don't copy peakfiles if
4926 * we're not copying media
4932 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4934 info << "attempting to make directory/folder " << to << endmsg;
4936 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4937 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4940 info << "attempting to copy " << from << " to " << to << endmsg;
4942 if (!copy_file (from, to)) {
4943 throw Glib::FileError (Glib::FileError::IO_ERROR,
4944 string_compose(_("\ncopying \"%1\" failed !"), from));
4949 /* measure file size even if we're not going to copy so that our Progress
4950 signals are correct, since we included these do-not-copy files
4951 in the computation of the total size and file count.
4955 g_stat (from.c_str(), &gsb);
4956 copied += gsb.st_size;
4959 double fraction = (double) copied / total_bytes;
4961 bool keep_going = true;
4963 if (saveas.copy_media) {
4965 /* no need or expectation of this if
4966 * media is not being copied, because
4967 * it will be fast(ish).
4970 /* tell someone "X percent, file M of N"; M is one-based */
4972 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4980 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4986 /* copy optional folders, if any */
4988 string old = plugins_dir ();
4989 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4990 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4991 copy_files (old, newdir);
4994 old = externals_dir ();
4995 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4996 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4997 copy_files (old, newdir);
5000 old = automation_dir ();
5001 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5002 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5003 copy_files (old, newdir);
5006 if (saveas.include_media) {
5008 if (saveas.copy_media) {
5009 #ifndef PLATFORM_WINDOWS
5010 /* There are problems with analysis files on
5011 * Windows, because they used a colon in their
5012 * names as late as 4.0. Colons are not legal
5013 * under Windows even if NTFS allows them.
5015 * This is a tricky problem to solve so for
5016 * just don't copy these files. They will be
5017 * regenerated as-needed anyway, subject to the
5018 * existing issue that the filenames will be
5019 * rejected by Windows, which is a separate
5020 * problem (though related).
5023 /* only needed if we are copying media, since the
5024 * analysis data refers to media data
5027 old = analysis_dir ();
5028 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5029 string newdir = Glib::build_filename (to_dir, "analysis");
5030 copy_files (old, newdir);
5032 #endif /* PLATFORM_WINDOWS */
5037 set_snapshot_name (saveas.new_name);
5038 _name = saveas.new_name;
5040 if (saveas.include_media && !saveas.copy_media) {
5042 /* reset search paths of the new session (which we're pretending to be right now) to
5043 include the original session search path, so we can still find all audio.
5046 if (internal_file_cnt) {
5047 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5048 ensure_search_path_includes (*s, DataType::AUDIO);
5049 cerr << "be sure to include " << *s << " for audio" << endl;
5052 /* we do not do this for MIDI because we copy
5053 all MIDI files if saveas.include_media is
5059 bool was_dirty = dirty ();
5061 save_default_options ();
5063 if (saveas.copy_media && saveas.copy_external) {
5064 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5065 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5069 saveas.final_session_folder_name = _path;
5071 store_recent_sessions (_name, _path);
5073 if (!saveas.switch_to) {
5075 /* save the new state */
5077 save_state ("", false, false, !saveas.include_media);
5079 /* switch back to the way things were */
5083 set_snapshot_name (old_snapshot);
5085 (*_session_dir) = old_sd;
5091 if (internal_file_cnt) {
5092 /* reset these to their original values */
5093 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5094 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5099 /* prune session dirs, and update disk space statistics
5104 session_dirs.clear ();
5105 session_dirs.push_back (sp);
5106 refresh_disk_space ();
5108 _writable = exists_and_writable (_path);
5110 /* ensure that all existing tracks reset their current capture source paths
5112 reset_write_sources (true, true);
5114 /* creating new write sources marks the session as
5115 dirty. If the new session is empty, then
5116 save_state() thinks we're saving a template and will
5117 not mark the session as clean. So do that here,
5118 before we save state.
5121 if (!saveas.include_media) {
5122 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5125 save_state ("", false, false, !saveas.include_media);
5127 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5128 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5131 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5132 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5138 if (fs->within_session()) {
5139 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5140 fs->set_path (newpath);
5145 } catch (Glib::FileError& e) {
5147 saveas.failure_message = e.what();
5149 /* recursively remove all the directories */
5151 remove_directory (to_dir);
5159 saveas.failure_message = _("unknown reason");
5161 /* recursively remove all the directories */
5163 remove_directory (to_dir);
5173 static void set_progress (Progress* p, size_t n, size_t t)
5175 p->set_progress (float (n) / float(t));
5179 Session::archive_session (const std::string& dest,
5180 const std::string& name,
5181 ArchiveEncode compress_audio,
5182 bool only_used_sources,
5185 if (dest.empty () || name.empty ()) {
5189 /* save current values */
5190 bool was_dirty = dirty ();
5191 string old_path = _path;
5192 string old_name = _name;
5193 string old_snapshot = _current_snapshot_name;
5194 string old_sd = _session_dir->root_path();
5195 string old_config_search_path[DataType::num_types];
5196 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5197 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5199 /* ensure that session-path is included in search-path */
5201 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5202 if ((*sd).path == old_path) {
5210 /* create temporary dir to save session to */
5211 #ifdef PLATFORM_WINDOWS
5212 char tmp[256] = "C:\\TEMP\\";
5213 GetTempPath (sizeof (tmp), tmp);
5215 char const* tmp = getenv("TMPDIR");
5220 if ((strlen (tmp) + 21) > 1024) {
5225 strcpy (tmptpl, tmp);
5226 strcat (tmptpl, "ardourarchive-XXXXXX");
5227 char* tmpdir = g_mkdtemp (tmptpl);
5233 std::string to_dir = std::string (tmpdir);
5235 /* switch session directory temporarily */
5236 (*_session_dir) = to_dir;
5238 if (!_session_dir->create()) {
5239 (*_session_dir) = old_sd;
5240 remove_directory (to_dir);
5244 /* prepare archive */
5245 string archive = Glib::build_filename (dest, name + ".tar.xz");
5247 PBD::ScopedConnectionList progress_connection;
5248 PBD::FileArchive ar (archive);
5250 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5253 /* collect files to archive */
5254 std::map<string,string> filemap;
5256 vector<string> do_not_copy_extensions;
5257 do_not_copy_extensions.push_back (statefile_suffix);
5258 do_not_copy_extensions.push_back (pending_suffix);
5259 do_not_copy_extensions.push_back (backup_suffix);
5260 do_not_copy_extensions.push_back (temp_suffix);
5261 do_not_copy_extensions.push_back (history_suffix);
5263 vector<string> blacklist_dirs;
5264 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5265 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5266 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5267 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5268 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5269 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5271 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5272 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5274 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5275 if (only_used_sources) {
5276 playlists->sync_all_regions_with_regions ();
5277 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5280 // collect audio sources for this session, calc total size for encoding
5281 // add option to only include *used* sources (see Session::cleanup_sources)
5282 size_t total_size = 0;
5284 Glib::Threads::Mutex::Lock lm (source_lock);
5285 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5286 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5287 if (!afs || afs->readable_length () == 0) {
5291 if (only_used_sources) {
5295 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5300 std::string from = afs->path();
5302 if (compress_audio != NO_ENCODE) {
5303 total_size += afs->readable_length ();
5305 if (afs->within_session()) {
5306 filemap[from] = make_new_media_path (from, name, name);
5308 filemap[from] = make_new_media_path (from, name, name);
5309 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5316 if (compress_audio != NO_ENCODE) {
5318 progress->set_progress (2); // set to "encoding"
5319 progress->set_progress (0);
5322 Glib::Threads::Mutex::Lock lm (source_lock);
5323 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5324 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5325 if (!afs || afs->readable_length () == 0) {
5329 if (only_used_sources) {
5333 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5338 orig_sources[afs] = afs->path();
5339 orig_gain[afs] = afs->gain();
5341 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5342 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5343 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5346 progress->descend ((float)afs->readable_length () / total_size);
5350 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5351 afs->replace_file (new_path);
5352 afs->set_gain (ns->gain(), true);
5355 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5359 progress->ascend ();
5365 progress->set_progress (-1); // set to "archiving"
5366 progress->set_progress (0);
5369 /* index files relevant for this session */
5370 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5371 vector<string> files;
5373 size_t prefix_len = (*sd).path.size();
5374 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5378 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5380 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5381 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5382 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5384 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5385 std::string from = *i;
5388 string filename = Glib::path_get_basename (from);
5389 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5390 if (filename == ".DS_STORE") {
5395 if (from.find (audiofile_dir_string) != string::npos) {
5397 } else if (from.find (midifile_dir_string) != string::npos) {
5398 filemap[from] = make_new_media_path (from, name, name);
5399 } else if (from.find (videofile_dir_string) != string::npos) {
5400 filemap[from] = make_new_media_path (from, name, name);
5402 bool do_copy = true;
5403 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5404 if (from.find (*v) != string::npos) {
5409 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5410 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5417 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5423 /* write session file */
5425 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5427 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5430 save_default_options ();
5432 size_t prefix_len = _path.size();
5433 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5437 /* collect session-state files */
5438 vector<string> files;
5439 do_not_copy_extensions.clear ();
5440 do_not_copy_extensions.push_back (history_suffix);
5442 blacklist_dirs.clear ();
5443 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5445 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5446 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5447 std::string from = *i;
5448 bool do_copy = true;
5449 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5450 if (from.find (*v) != string::npos) {
5455 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5456 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5462 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5466 /* restore original values */
5469 set_snapshot_name (old_snapshot);
5470 (*_session_dir) = old_sd;
5474 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5475 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5477 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5478 i->first->replace_file (i->second);
5480 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5481 i->first->set_gain (i->second, true);
5484 int rv = ar.create (filemap);
5485 remove_directory (to_dir);
5491 Session::undo (uint32_t n)
5493 if (actively_recording()) {
5501 Session::redo (uint32_t n)
5503 if (actively_recording()) {