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_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/disk_reader.h"
93 #include "ardour/filename_extensions.h"
94 #include "ardour/graph.h"
95 #include "ardour/location.h"
97 #include "ardour/lv2_plugin.h"
99 #include "ardour/midi_model.h"
100 #include "ardour/midi_patch_manager.h"
101 #include "ardour/midi_region.h"
102 #include "ardour/midi_scene_changer.h"
103 #include "ardour/midi_source.h"
104 #include "ardour/midi_track.h"
105 #include "ardour/pannable.h"
106 #include "ardour/playlist_factory.h"
107 #include "ardour/playlist_source.h"
108 #include "ardour/port.h"
109 #include "ardour/processor.h"
110 #include "ardour/progress.h"
111 #include "ardour/profile.h"
112 #include "ardour/proxy_controllable.h"
113 #include "ardour/recent_sessions.h"
114 #include "ardour/region_factory.h"
115 #include "ardour/revision.h"
116 #include "ardour/route_group.h"
117 #include "ardour/send.h"
118 #include "ardour/selection.h"
119 #include "ardour/session.h"
120 #include "ardour/session_directory.h"
121 #include "ardour/session_metadata.h"
122 #include "ardour/session_playlists.h"
123 #include "ardour/session_state_utils.h"
124 #include "ardour/silentfilesource.h"
125 #include "ardour/smf_source.h"
126 #include "ardour/sndfilesource.h"
127 #include "ardour/source_factory.h"
128 #include "ardour/speakers.h"
129 #include "ardour/template_utils.h"
130 #include "ardour/tempo.h"
131 #include "ardour/ticker.h"
132 #include "ardour/types_convert.h"
133 #include "ardour/user_bundle.h"
134 #include "ardour/vca.h"
135 #include "ardour/vca_manager.h"
137 #include "control_protocol/control_protocol.h"
139 #include "LuaBridge/LuaBridge.h"
141 #include "pbd/i18n.h"
145 using namespace ARDOUR;
148 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
151 Session::pre_engine_init (string fullpath)
153 if (fullpath.empty()) {
155 throw failed_constructor();
158 /* discover canonical fullpath */
160 _path = canonical_path(fullpath);
163 if (Profile->get_trx() ) {
164 // Waves TracksLive has a usecase of session replacement with a new one.
165 // We should check session state file (<session_name>.ardour) existance
166 // to determine if the session is new or not
168 string full_session_name = Glib::build_filename( fullpath, _name );
169 full_session_name += statefile_suffix;
171 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
173 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
176 /* finish initialization that can't be done in a normal C++ constructor
180 timerclear (&last_mmc_step);
181 g_atomic_int_set (&processing_prohibited, 0);
182 g_atomic_int_set (&_record_status, Disabled);
183 g_atomic_int_set (&_playback_load, 100);
184 g_atomic_int_set (&_capture_load, 100);
186 _all_route_group->set_active (true, this);
187 interpolation.add_channel_to (0, 0);
189 if (config.get_use_video_sync()) {
190 waiting_for_sync_offset = true;
192 waiting_for_sync_offset = false;
195 last_rr_session_dir = session_dirs.begin();
197 set_history_depth (Config->get_history_depth());
199 /* default: assume simple stereo speaker configuration */
201 _speakers->setup_default_speakers (2);
203 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
204 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
205 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
206 add_controllable (_solo_cut_control);
208 /* These are all static "per-class" signals */
210 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
211 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
212 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
213 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
214 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
216 /* stop IO objects from doing stuff until we're ready for them */
218 Delivery::disable_panners ();
219 IO::disable_connecting ();
223 Session::post_engine_init ()
225 BootMessage (_("Set block size and sample rate"));
227 set_block_size (_engine.samples_per_cycle());
228 set_frame_rate (_engine.sample_rate());
230 BootMessage (_("Using configuration"));
232 _midi_ports = new MidiPortManager;
234 MIDISceneChanger* msc;
236 _scene_changer = msc = new MIDISceneChanger (*this);
237 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
238 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
240 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
241 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
243 setup_midi_machine_control ();
245 if (_butler->start_thread()) {
246 error << _("Butler did not start") << endmsg;
250 if (start_midi_thread ()) {
251 error << _("MIDI I/O thread did not start") << endmsg;
255 setup_click_sounds (0);
256 setup_midi_control ();
258 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
259 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
262 /* tempo map requires sample rate knowledge */
265 _tempo_map = new TempoMap (_current_frame_rate);
266 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
267 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
268 } catch (std::exception const & e) {
269 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
272 error << _("Unknown exception during session setup") << endmsg;
277 /* MidiClock requires a tempo map */
280 midi_clock = new MidiClockTicker ();
281 midi_clock->set_session (this);
283 /* crossfades require sample rate knowledge */
285 SndFileSource::setup_standard_crossfades (*this, frame_rate());
286 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
287 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
289 DiskReader::allocate_working_buffers();
290 refresh_disk_space ();
292 /* we're finally ready to call set_state() ... all objects have
293 * been created, the engine is running.
298 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
299 error << _("Could not set session state from XML") << endmsg;
302 } catch (PBD::unknown_enumeration& e) {
303 error << _("Session state: ") << e.what() << endmsg;
307 // set_state() will call setup_raid_path(), but if it's a new session we need
308 // to call setup_raid_path() here.
309 setup_raid_path (_path);
314 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
315 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
317 Config->map_parameters (ff);
318 config.map_parameters (ft);
319 _butler->map_parameters ();
321 /* Reset all panners */
323 Delivery::reset_panners ();
325 /* this will cause the CPM to instantiate any protocols that are in use
326 * (or mandatory), which will pass it this Session, and then call
327 * set_state() on each instantiated protocol to match stored state.
330 ControlProtocolManager::instance().set_session (this);
332 /* This must be done after the ControlProtocolManager set_session above,
333 as it will set states for ports which the ControlProtocolManager creates.
336 // XXX set state of MIDI::Port's
337 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
339 /* And this must be done after the MIDI::Manager::set_port_states as
340 * it will try to make connections whose details are loaded by set_port_states.
345 /* Let control protocols know that we are now all connected, so they
346 * could start talking to surfaces if they want to.
349 ControlProtocolManager::instance().midi_connectivity_established ();
351 if (_is_new && !no_auto_connect()) {
352 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
353 auto_connect_master_bus ();
356 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
358 /* update latencies */
360 initialize_latencies ();
362 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
363 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
364 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
366 } catch (AudioEngine::PortRegistrationFailure& err) {
367 error << err.what() << endmsg;
369 } catch (std::exception const & e) {
370 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
373 error << _("Unknown exception during session setup") << endmsg;
377 BootMessage (_("Reset Remote Controls"));
379 // send_full_time_code (0);
380 _engine.transport_locate (0);
382 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
383 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
385 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
388 /* initial program change will be delivered later; see ::config_changed() */
390 _state_of_the_state = Clean;
392 Port::set_connecting_blocked (false);
394 DirtyChanged (); /* EMIT SIGNAL */
398 } else if (state_was_pending) {
400 remove_pending_capture_state ();
401 state_was_pending = false;
404 /* Now, finally, we can fill the playback buffers */
406 BootMessage (_("Filling playback buffers"));
408 boost::shared_ptr<RouteList> rl = routes.reader();
409 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
410 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
411 if (trk && !trk->is_private_route()) {
412 trk->seek (_transport_frame, true);
420 Session::session_loaded ()
424 _state_of_the_state = Clean;
426 DirtyChanged (); /* EMIT SIGNAL */
430 } else if (state_was_pending) {
432 remove_pending_capture_state ();
433 state_was_pending = false;
436 /* Now, finally, we can fill the playback buffers */
438 BootMessage (_("Filling playback buffers"));
439 force_locate (_transport_frame, false);
443 Session::raid_path () const
445 Searchpath raid_search_path;
447 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
448 raid_search_path += (*i).path;
451 return raid_search_path.to_string ();
455 Session::setup_raid_path (string path)
464 session_dirs.clear ();
466 Searchpath search_path(path);
467 Searchpath sound_search_path;
468 Searchpath midi_search_path;
470 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
472 sp.blocks = 0; // not needed
473 session_dirs.push_back (sp);
475 SessionDirectory sdir(sp.path);
477 sound_search_path += sdir.sound_path ();
478 midi_search_path += sdir.midi_path ();
481 // reset the round-robin soundfile path thingie
482 last_rr_session_dir = session_dirs.begin();
486 Session::path_is_within_session (const std::string& path)
488 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
489 if (PBD::path_is_within (i->path, path)) {
497 Session::ensure_subdirs ()
501 dir = session_directory().peak_path();
503 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
504 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
508 dir = session_directory().sound_path();
510 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
511 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
515 dir = session_directory().midi_path();
517 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
518 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
522 dir = session_directory().dead_path();
524 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
525 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
529 dir = session_directory().export_path();
531 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
532 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
536 dir = analysis_dir ();
538 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
539 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
543 dir = plugins_dir ();
545 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
546 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
550 dir = externals_dir ();
552 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
553 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
560 /** @param session_template directory containing session template, or empty.
561 * Caller must not hold process lock.
564 Session::create (const string& session_template, BusProfile* bus_profile)
566 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
567 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
571 if (ensure_subdirs ()) {
575 _writable = exists_and_writable (_path);
577 if (!session_template.empty()) {
578 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
580 FILE* in = g_fopen (in_path.c_str(), "rb");
583 /* no need to call legalize_for_path() since the string
584 * in session_template is already a legal path name
586 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
588 FILE* out = g_fopen (out_path.c_str(), "wb");
592 stringstream new_session;
595 size_t charsRead = fread (buf, sizeof(char), 1024, in);
598 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
603 if (charsRead == 0) {
606 new_session.write (buf, charsRead);
610 string file_contents = new_session.str();
611 size_t writeSize = file_contents.length();
612 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
613 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
621 if (!ARDOUR::Profile->get_trx()) {
622 /* Copy plugin state files from template to new session */
623 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
624 copy_recurse (template_plugins, plugins_dir ());
630 error << string_compose (_("Could not open %1 for writing session template"), out_path)
637 error << string_compose (_("Could not open session template %1 for reading"), in_path)
644 if (Profile->get_trx()) {
646 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
647 * Remember that this is a brand new session. Sessions
648 * loaded from saved state will get this range from the saved state.
651 set_session_range_location (0, 0);
653 /* Initial loop location, from absolute zero, length 10 seconds */
655 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
656 _locations->add (loc, true);
657 set_auto_loop_location (loc);
660 _state_of_the_state = Clean;
662 /* set up Master Out and Monitor Out if necessary */
666 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
667 if (bus_profile->master_out_channels) {
668 int rv = add_master_bus (count);
674 if (Config->get_use_monitor_bus())
675 add_monitor_section ();
683 Session::maybe_write_autosave()
685 if (dirty() && record_status() != Recording) {
686 save_state("", true);
691 Session::remove_pending_capture_state ()
693 std::string pending_state_file_path(_session_dir->root_path());
695 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
697 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
699 if (g_remove (pending_state_file_path.c_str()) != 0) {
700 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
701 pending_state_file_path, g_strerror (errno)) << endmsg;
705 /** Rename a state file.
706 * @param old_name Old snapshot name.
707 * @param new_name New snapshot name.
710 Session::rename_state (string old_name, string new_name)
712 if (old_name == _current_snapshot_name || old_name == _name) {
713 /* refuse to rename the current snapshot or the "main" one */
717 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
718 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
720 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
721 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
723 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
724 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
725 old_name, new_name, g_strerror(errno)) << endmsg;
729 /** Remove a state file.
730 * @param snapshot_name Snapshot name.
733 Session::remove_state (string snapshot_name)
735 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
736 // refuse to remove the current snapshot or the "main" one
740 std::string xml_path(_session_dir->root_path());
742 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
744 if (!create_backup_file (xml_path)) {
745 // don't remove it if a backup can't be made
746 // create_backup_file will log the error.
751 if (g_remove (xml_path.c_str()) != 0) {
752 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
753 xml_path, g_strerror (errno)) << endmsg;
757 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
759 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
761 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
764 std::string xml_path(_session_dir->root_path());
766 /* prevent concurrent saves from different threads */
768 Glib::Threads::Mutex::Lock lm (save_state_lock);
770 if (!_writable || (_state_of_the_state & CannotSave)) {
774 if (g_atomic_int_get(&_suspend_save)) {
778 _save_queued = false;
780 snapshot_t fork_state = NormalSave;
781 if (!snapshot_name.empty() && snapshot_name != _current_snapshot_name && !template_only && !pending) {
782 /* snapshot, close midi */
783 fork_state = switch_to_snapshot ? SwitchToSnapshot : SnapshotKeep;
787 const int64_t save_start_time = g_get_monotonic_time();
790 /* tell sources we're saving first, in case they write out to a new file
791 * which should be saved with the state rather than the old one */
792 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
794 i->second->session_saved();
795 } catch (Evoral::SMF::FileError& e) {
796 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
800 SessionSaveUnderway (); /* EMIT SIGNAL */
802 bool mark_as_clean = true;
804 if (!snapshot_name.empty() && !switch_to_snapshot) {
805 mark_as_clean = false;
809 mark_as_clean = false;
810 tree.set_root (&get_template());
812 tree.set_root (&state (true, fork_state));
815 if (snapshot_name.empty()) {
816 snapshot_name = _current_snapshot_name;
817 } else if (switch_to_snapshot) {
818 set_snapshot_name (snapshot_name);
821 assert (!snapshot_name.empty());
825 /* proper save: use statefile_suffix (.ardour in English) */
827 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
829 /* make a backup copy of the old file */
831 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
832 // create_backup_file will log the error
838 /* pending save: use pending_suffix (.pending in English) */
839 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
842 std::string tmp_path(_session_dir->root_path());
843 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
845 cerr << "actually writing state to " << tmp_path << endl;
847 if (!tree.write (tmp_path)) {
848 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
849 if (g_remove (tmp_path.c_str()) != 0) {
850 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
851 tmp_path, g_strerror (errno)) << endmsg;
857 cerr << "renaming state to " << xml_path << endl;
859 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
860 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
861 tmp_path, xml_path, g_strerror(errno)) << endmsg;
862 if (g_remove (tmp_path.c_str()) != 0) {
863 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
864 tmp_path, g_strerror (errno)) << endmsg;
872 save_history (snapshot_name);
875 bool was_dirty = dirty();
877 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
880 DirtyChanged (); /* EMIT SIGNAL */
884 StateSaved (snapshot_name); /* EMIT SIGNAL */
888 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
889 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
895 Session::restore_state (string snapshot_name)
898 if (load_state (snapshot_name) == 0) {
899 set_state (*state_tree->root(), Stateful::loading_state_version);
903 // unknown_enumeration
911 Session::load_state (string snapshot_name)
916 state_was_pending = false;
918 /* check for leftover pending state from a crashed capture attempt */
920 std::string xmlpath(_session_dir->root_path());
921 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
923 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
925 /* there is pending state from a crashed capture attempt */
927 boost::optional<int> r = AskAboutPendingState();
928 if (r.get_value_or (1)) {
929 state_was_pending = true;
933 if (!state_was_pending) {
934 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
937 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
938 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
939 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
940 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
945 state_tree = new XMLTree;
949 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
951 if (!state_tree->read (xmlpath)) {
952 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
958 XMLNode const & root (*state_tree->root());
960 if (root.name() != X_("Session")) {
961 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
968 root.get_property ("version", version);
969 Stateful::loading_state_version = parse_stateful_loading_version (version);
971 if ((Stateful::loading_state_version / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
972 cerr << "Session-version: " << Stateful::loading_state_version << " is not supported. Current: " << CURRENT_SESSION_FILE_VERSION << "\n";
973 throw SessionException (string_compose (_("Incomatible Session Version. That session was created with a newer version of %1"), PROGRAM_NAME));
976 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
978 std::string backup_path(_session_dir->root_path());
979 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
980 backup_path = Glib::build_filename (backup_path, backup_filename);
982 // only create a backup for a given statefile version once
984 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
986 VersionMismatch (xmlpath, backup_path);
988 if (!copy_file (xmlpath, backup_path)) {;
994 save_snapshot_name (snapshot_name);
1000 Session::load_options (const XMLNode& node)
1002 config.set_variables (node);
1007 Session::save_default_options ()
1009 return config.save_state();
1013 Session::get_state()
1019 Session::get_template()
1021 /* if we don't disable rec-enable, diskstreams
1022 will believe they need to store their capture
1023 sources in their state node.
1026 disable_record (false);
1028 return state(false);
1031 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1032 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1035 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1037 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1040 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1044 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1047 XMLNode* node = new XMLNode("TrackState"); // XXX
1050 PlaylistSet playlists; // SessionPlaylists
1053 // these will work with new_route_from_template()
1054 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1055 child = node->add_child ("Routes");
1056 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1057 if ((*i)->is_auditioner()) {
1060 if ((*i)->is_master() || (*i)->is_monitor()) {
1063 child->add_child_nocopy ((*i)->get_state());
1064 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1066 playlists.insert (track->playlist ());
1070 // on load, Regions in the playlists need to resolve and map Source-IDs
1071 // also playlist needs to be merged or created with new-name..
1072 // ... and Diskstream in tracks adjusted to use the correct playlist
1073 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1074 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1075 child->add_child_nocopy ((*i)->get_state ());
1076 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1077 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1078 const Region::SourceList& sl = (*s)->sources ();
1079 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1080 sources.insert (*sli);
1085 child = node->add_child ("Sources");
1086 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1087 child->add_child_nocopy ((*i)->get_state ());
1088 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1090 #ifdef PLATFORM_WINDOWS
1093 string p = fs->path ();
1094 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1098 std::string sn = Glib::build_filename (path, "share.axml");
1101 tree.set_root (node);
1102 return tree.write (sn.c_str());
1107 struct route_id_compare {
1109 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1111 return r1->id () < r2->id ();
1117 Session::state (bool full_state, snapshot_t snapshot_type)
1120 XMLNode* node = new XMLNode("Session");
1123 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1125 child = node->add_child ("ProgramVersion");
1126 child->set_property("created-with", created_with);
1128 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1129 child->set_property("modified-with", modified_with);
1131 /* store configuration settings */
1135 node->set_property ("name", _name);
1136 node->set_property ("sample-rate", _base_frame_rate);
1138 if (session_dirs.size() > 1) {
1142 vector<space_and_path>::iterator i = session_dirs.begin();
1143 vector<space_and_path>::iterator next;
1145 ++i; /* skip the first one */
1149 while (i != session_dirs.end()) {
1153 if (next != session_dirs.end()) {
1154 p += G_SEARCHPATH_SEPARATOR;
1163 child = node->add_child ("Path");
1164 child->add_content (p);
1166 node->set_property ("end-is-free", _session_range_end_is_free);
1169 /* save the ID counter */
1171 node->set_property ("id-counter", ID::counter());
1173 node->set_property ("name-counter", name_id_counter ());
1175 /* save the event ID counter */
1177 node->set_property ("event-counter", Evoral::event_id_counter());
1179 /* save the VCA counter */
1181 node->set_property ("vca-counter", VCA::get_next_vca_number());
1183 /* various options */
1185 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1186 if (!midi_port_nodes.empty()) {
1187 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1188 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1189 midi_port_stuff->add_child_nocopy (**n);
1191 node->add_child_nocopy (*midi_port_stuff);
1194 XMLNode& cfgxml (config.get_variables ());
1196 /* exclude search-paths from template */
1197 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1198 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1199 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1201 node->add_child_nocopy (cfgxml);
1203 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1205 child = node->add_child ("Sources");
1208 Glib::Threads::Mutex::Lock sl (source_lock);
1210 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1212 /* Don't save information about non-file Sources, or
1213 * about non-destructive file sources that are empty
1214 * and unused by any regions.
1216 boost::shared_ptr<FileSource> fs;
1218 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) == 0) {
1222 if (!fs->destructive()) {
1223 if (fs->empty() && !fs->used()) {
1228 if (snapshot_type != NormalSave && fs->within_session ()) {
1229 /* copy MIDI sources to new file
1231 * We cannot replace the midi-source and MidiRegion::clobber_sources,
1232 * because the GUI (midi_region) has a direct pointer to the midi-model
1233 * of the source, as does UndoTransaction.
1235 * On the upside, .mid files are not kept open. The file is only open
1236 * when reading the model initially and when flushing the model to disk:
1237 * source->session_saved () or export.
1239 * We can change the _path of the existing source under the hood, keeping
1240 * all IDs, references and pointers intact.
1242 boost::shared_ptr<SMFSource> ms;
1243 if ((ms = boost::dynamic_pointer_cast<SMFSource> (siter->second)) != 0) {
1244 const std::string ancestor_name = ms->ancestor_name();
1245 const std::string base = PBD::basename_nosuffix(ancestor_name);
1246 const string path = new_midi_source_path (base, false);
1248 /* use SMF-API to clone data (use the midi_model, not data on disk) */
1249 boost::shared_ptr<SMFSource> newsrc (new SMFSource (*this, path, SndFileSource::default_writable_flags));
1250 Source::Lock lm (ms->mutex());
1252 // TODO special-case empty, removable() files: just create a new removable.
1253 // (load + write flushes the model and creates the file)
1255 ms->load_model (lm);
1257 if (ms->write_to (lm, newsrc, Evoral::MinBeats, Evoral::MaxBeats)) {
1258 error << string_compose (_("Session-Save: Failed to copy MIDI Source '%1' for snapshot"), ancestor_name) << endmsg;
1260 if (snapshot_type == SnapshotKeep) {
1261 /* keep working on current session.
1263 * Save snapshot-state with the original filename.
1264 * Switch to use new path for future saves of the main session.
1266 child->add_child_nocopy (ms->get_state());
1270 * ~SMFSource unlinks removable() files.
1272 std::string npath (ms->path ());
1273 ms->replace_file (newsrc->path ());
1274 newsrc->replace_file (npath);
1276 if (snapshot_type == SwitchToSnapshot) {
1277 /* save and switch to snapshot.
1279 * Leave the old file in place (as is).
1280 * Snapshot uses new source directly
1282 child->add_child_nocopy (ms->get_state());
1289 child->add_child_nocopy (siter->second->get_state());
1293 child = node->add_child ("Regions");
1296 Glib::Threads::Mutex::Lock rl (region_lock);
1297 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1298 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1299 boost::shared_ptr<Region> r = i->second;
1300 /* only store regions not attached to playlists */
1301 if (r->playlist() == 0) {
1302 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1303 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1305 child->add_child_nocopy (r->get_state ());
1310 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1312 if (!cassocs.empty()) {
1313 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1315 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1316 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1317 can->set_property (X_("copy"), i->first->id());
1318 can->set_property (X_("original"), i->second->id());
1319 ca->add_child_nocopy (*can);
1326 node->add_child_nocopy (_selection->get_state());
1329 node->add_child_nocopy (_locations->get_state());
1332 Locations loc (*this);
1333 const bool was_dirty = dirty();
1334 // for a template, just create a new Locations, populate it
1335 // with the default start and end, and get the state for that.
1336 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1337 range->set (max_framepos, 0);
1339 XMLNode& locations_state = loc.get_state();
1341 if (ARDOUR::Profile->get_trx() && _locations) {
1342 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1343 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1344 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1345 locations_state.add_child_nocopy ((*i)->get_state ());
1349 node->add_child_nocopy (locations_state);
1351 /* adding a location above will have marked the session
1352 * dirty. This is an artifact, so fix it if the session wasn't
1357 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1361 child = node->add_child ("Bundles");
1363 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1364 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1365 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1367 child->add_child_nocopy (b->get_state());
1372 node->add_child_nocopy (_vca_manager->get_state());
1374 child = node->add_child ("Routes");
1376 boost::shared_ptr<RouteList> r = routes.reader ();
1378 route_id_compare cmp;
1379 RouteList xml_node_order (*r);
1380 xml_node_order.sort (cmp);
1382 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1383 if (!(*i)->is_auditioner()) {
1385 child->add_child_nocopy ((*i)->get_state());
1387 child->add_child_nocopy ((*i)->get_template());
1393 playlists->add_state (node, full_state);
1395 child = node->add_child ("RouteGroups");
1396 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1397 child->add_child_nocopy ((*i)->get_state());
1401 XMLNode* gain_child = node->add_child ("Click");
1402 gain_child->add_child_nocopy (_click_io->state (full_state));
1403 gain_child->add_child_nocopy (_click_gain->state (full_state));
1407 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1408 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1412 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1413 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1416 node->add_child_nocopy (_speakers->get_state());
1417 node->add_child_nocopy (_tempo_map->get_state());
1418 node->add_child_nocopy (get_control_protocol_state());
1421 node->add_child_copy (*_extra_xml);
1425 Glib::Threads::Mutex::Lock lm (lua_lock);
1428 luabridge::LuaRef savedstate ((*_lua_save)());
1429 saved = savedstate.cast<std::string>();
1431 lua.collect_garbage ();
1434 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1435 std::string b64s (b64);
1438 XMLNode* script_node = new XMLNode (X_("Script"));
1439 script_node->set_property (X_("lua"), LUA_VERSION);
1440 script_node->add_content (b64s);
1441 node->add_child_nocopy (*script_node);
1448 Session::get_control_protocol_state ()
1450 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1451 return cpm.get_state();
1455 Session::set_state (const XMLNode& node, int version)
1462 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1464 if (node.name() != X_("Session")) {
1465 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1469 node.get_property ("name", _name);
1471 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1473 _nominal_frame_rate = _base_frame_rate;
1475 assert (AudioEngine::instance()->running ());
1476 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1477 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1478 if (r.get_value_or (0)) {
1484 created_with = "unknown";
1485 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1486 child->get_property (X_("created-with"), created_with);
1489 setup_raid_path(_session_dir->root_path());
1491 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1494 if (node.get_property (X_("id-counter"), counter)) {
1495 ID::init_counter (counter);
1497 /* old sessions used a timebased counter, so fake
1498 * the startup ID counter based on a standard
1503 ID::init_counter (now);
1506 if (node.get_property (X_("name-counter"), counter)) {
1507 init_name_id_counter (counter);
1510 if (node.get_property (X_("event-counter"), counter)) {
1511 Evoral::init_event_id_counter (counter);
1514 if (node.get_property (X_("vca-counter"), counter)) {
1515 VCA::set_next_vca_number (counter);
1517 VCA::set_next_vca_number (1);
1520 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1521 _midi_ports->set_midi_port_states (child->children());
1524 IO::disable_connecting ();
1526 Stateful::save_extra_xml (node);
1528 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1529 load_options (*child);
1530 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1531 load_options (*child);
1533 error << _("Session: XML state has no options section") << endmsg;
1536 if (version >= 3000) {
1537 if ((child = find_named_node (node, "Metadata")) == 0) {
1538 warning << _("Session: XML state has no metadata section") << endmsg;
1539 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1544 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1545 _speakers->set_state (*child, version);
1548 if ((child = find_named_node (node, "Sources")) == 0) {
1549 error << _("Session: XML state has no sources section") << endmsg;
1551 } else if (load_sources (*child)) {
1555 if ((child = find_named_node (node, "TempoMap")) == 0) {
1556 error << _("Session: XML state has no Tempo Map section") << endmsg;
1558 } else if (_tempo_map->set_state (*child, version)) {
1562 if ((child = find_named_node (node, "Locations")) == 0) {
1563 error << _("Session: XML state has no locations section") << endmsg;
1565 } else if (_locations->set_state (*child, version)) {
1569 locations_changed ();
1571 if (_session_range_location) {
1572 AudioFileSource::set_header_position_offset (_session_range_location->start());
1575 if ((child = find_named_node (node, "Regions")) == 0) {
1576 error << _("Session: XML state has no Regions section") << endmsg;
1578 } else if (load_regions (*child)) {
1582 if ((child = find_named_node (node, "Playlists")) == 0) {
1583 error << _("Session: XML state has no playlists section") << endmsg;
1585 } else if (playlists->load (*this, *child)) {
1589 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1591 } else if (playlists->load_unused (*this, *child)) {
1595 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1596 if (load_compounds (*child)) {
1601 if (version >= 3000) {
1602 if ((child = find_named_node (node, "Bundles")) == 0) {
1603 warning << _("Session: XML state has no bundles section") << endmsg;
1606 /* We can't load Bundles yet as they need to be able
1607 * to convert from port names to Port objects, which can't happen until
1609 _bundle_xml_node = new XMLNode (*child);
1613 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1614 _vca_manager->set_state (*child, version);
1617 if ((child = find_named_node (node, "Routes")) == 0) {
1618 error << _("Session: XML state has no routes section") << endmsg;
1620 } else if (load_routes (*child, version)) {
1624 /* Now that we have Routes and masters loaded, connect them if appropriate */
1626 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1628 if (version >= 3000) {
1630 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1631 error << _("Session: XML state has no route groups section") << endmsg;
1633 } else if (load_route_groups (*child, version)) {
1637 } else if (version < 3000) {
1639 if ((child = find_named_node (node, "EditGroups")) == 0) {
1640 error << _("Session: XML state has no edit groups section") << endmsg;
1642 } else if (load_route_groups (*child, version)) {
1646 if ((child = find_named_node (node, "MixGroups")) == 0) {
1647 error << _("Session: XML state has no mix groups section") << endmsg;
1649 } else if (load_route_groups (*child, version)) {
1654 if ((child = find_named_node (node, "Click")) == 0) {
1655 warning << _("Session: XML state has no click section") << endmsg;
1656 } else if (_click_io) {
1657 setup_click_state (&node);
1660 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1661 ControlProtocolManager::instance().set_state (*child, version);
1664 if ((child = find_named_node (node, "Script"))) {
1665 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1666 if (!(*n)->is_content ()) { continue; }
1668 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1670 Glib::Threads::Mutex::Lock lm (lua_lock);
1671 (*_lua_load)(std::string ((const char*)buf, size));
1672 } catch (luabridge::LuaException const& e) {
1673 cerr << "LuaException:" << e.what () << endl;
1679 if ((child = find_named_node (node, X_("Selection")))) {
1680 _selection->set_state (*child, version);
1683 update_route_record_state ();
1685 /* here beginneth the second phase ... */
1686 set_snapshot_name (_current_snapshot_name);
1688 StateReady (); /* EMIT SIGNAL */
1701 Session::load_routes (const XMLNode& node, int version)
1704 XMLNodeConstIterator niter;
1705 RouteList new_routes;
1707 nlist = node.children();
1711 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1713 boost::shared_ptr<Route> route;
1715 if (version < 3000) {
1716 route = XMLRouteFactory_2X (**niter, version);
1717 } else if (version < 5000) {
1718 route = XMLRouteFactory_3X (**niter, version);
1720 route = XMLRouteFactory (**niter, version);
1724 error << _("Session: cannot create Route from XML description.") << endmsg;
1728 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1730 new_routes.push_back (route);
1733 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1735 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1737 BootMessage (_("Finished adding tracks/busses"));
1742 boost::shared_ptr<Route>
1743 Session::XMLRouteFactory (const XMLNode& node, int version)
1745 boost::shared_ptr<Route> ret;
1747 if (node.name() != "Route") {
1751 XMLProperty const * pl_prop = node.property (X_("audio-playlist"));
1754 pl_prop = node.property (X_("midi-playlist"));
1757 DataType type = DataType::AUDIO;
1758 node.get_property("default-type", type);
1760 assert (type != DataType::NIL);
1764 /* has at least 1 playlist, therefore a track ... */
1766 boost::shared_ptr<Track> track;
1768 if (type == DataType::AUDIO) {
1769 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1771 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1774 if (track->init()) {
1778 if (track->set_state (node, version)) {
1782 BOOST_MARK_TRACK (track);
1786 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1787 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1790 if (r->init () == 0 && r->set_state (node, version) == 0) {
1791 BOOST_MARK_ROUTE (r);
1799 boost::shared_ptr<Route>
1800 Session::XMLRouteFactory_3X (const XMLNode& node, int version)
1802 boost::shared_ptr<Route> ret;
1804 if (node.name() != "Route") {
1808 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1810 DataType type = DataType::AUDIO;
1811 node.get_property("default-type", type);
1813 assert (type != DataType::NIL);
1817 boost::shared_ptr<Track> track;
1819 if (type == DataType::AUDIO) {
1820 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1822 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1825 if (track->init()) {
1829 if (track->set_state (node, version)) {
1833 BOOST_MARK_TRACK (track);
1837 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1838 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1840 if (r->init () == 0 && r->set_state (node, version) == 0) {
1841 BOOST_MARK_ROUTE (r);
1849 boost::shared_ptr<Route>
1850 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1852 boost::shared_ptr<Route> ret;
1854 if (node.name() != "Route") {
1858 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1860 ds_prop = node.property (X_("diskstream"));
1863 DataType type = DataType::AUDIO;
1864 node.get_property("default-type", type);
1866 assert (type != DataType::NIL);
1870 /* see comment in current ::set_state() regarding diskstream
1871 * state and DiskReader/DiskWRiter.
1874 error << _("Could not find diskstream for route") << endmsg;
1875 return boost::shared_ptr<Route> ();
1877 boost::shared_ptr<Track> track;
1879 if (type == DataType::AUDIO) {
1880 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1882 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1885 if (track->init()) {
1889 if (track->set_state (node, version)) {
1893 BOOST_MARK_TRACK (track);
1897 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1898 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1900 if (r->init () == 0 && r->set_state (node, version) == 0) {
1901 BOOST_MARK_ROUTE (r);
1910 Session::load_regions (const XMLNode& node)
1913 XMLNodeConstIterator niter;
1914 boost::shared_ptr<Region> region;
1916 nlist = node.children();
1920 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1921 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1922 error << _("Session: cannot create Region from XML description.");
1923 XMLProperty const * name = (**niter).property("name");
1926 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1937 Session::load_compounds (const XMLNode& node)
1939 XMLNodeList calist = node.children();
1940 XMLNodeConstIterator caiter;
1941 XMLProperty const * caprop;
1943 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1944 XMLNode* ca = *caiter;
1948 if ((caprop = ca->property (X_("original"))) == 0) {
1951 orig_id = caprop->value();
1953 if ((caprop = ca->property (X_("copy"))) == 0) {
1956 copy_id = caprop->value();
1958 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1959 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1961 if (!orig || !copy) {
1962 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1968 RegionFactory::add_compound_association (orig, copy);
1975 Session::load_nested_sources (const XMLNode& node)
1978 XMLNodeConstIterator niter;
1980 nlist = node.children();
1982 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1983 if ((*niter)->name() == "Source") {
1985 /* it may already exist, so don't recreate it unnecessarily
1988 XMLProperty const * prop = (*niter)->property (X_("id"));
1990 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1994 ID source_id (prop->value());
1996 if (!source_by_id (source_id)) {
1999 SourceFactory::create (*this, **niter, true);
2001 catch (failed_constructor& err) {
2002 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
2009 boost::shared_ptr<Region>
2010 Session::XMLRegionFactory (const XMLNode& node, bool full)
2012 XMLProperty const * type = node.property("type");
2016 const XMLNodeList& nlist = node.children();
2018 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
2019 XMLNode *child = (*niter);
2020 if (child->name() == "NestedSource") {
2021 load_nested_sources (*child);
2025 if (!type || type->value() == "audio") {
2026 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
2027 } else if (type->value() == "midi") {
2028 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
2031 } catch (failed_constructor& err) {
2032 return boost::shared_ptr<Region> ();
2035 return boost::shared_ptr<Region> ();
2038 boost::shared_ptr<AudioRegion>
2039 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
2041 XMLProperty const * prop;
2042 boost::shared_ptr<Source> source;
2043 boost::shared_ptr<AudioSource> as;
2045 SourceList master_sources;
2046 uint32_t nchans = 1;
2049 if (node.name() != X_("Region")) {
2050 return boost::shared_ptr<AudioRegion>();
2053 node.get_property (X_("channels"), nchans);
2055 if ((prop = node.property ("name")) == 0) {
2056 cerr << "no name for this region\n";
2060 if ((prop = node.property (X_("source-0"))) == 0) {
2061 if ((prop = node.property ("source")) == 0) {
2062 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
2063 return boost::shared_ptr<AudioRegion>();
2067 PBD::ID s_id (prop->value());
2069 if ((source = source_by_id (s_id)) == 0) {
2070 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
2071 return boost::shared_ptr<AudioRegion>();
2074 as = boost::dynamic_pointer_cast<AudioSource>(source);
2076 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
2077 return boost::shared_ptr<AudioRegion>();
2080 sources.push_back (as);
2082 /* pickup other channels */
2084 for (uint32_t n=1; n < nchans; ++n) {
2085 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2086 if ((prop = node.property (buf)) != 0) {
2088 PBD::ID id2 (prop->value());
2090 if ((source = source_by_id (id2)) == 0) {
2091 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2092 return boost::shared_ptr<AudioRegion>();
2095 as = boost::dynamic_pointer_cast<AudioSource>(source);
2097 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2098 return boost::shared_ptr<AudioRegion>();
2100 sources.push_back (as);
2104 for (uint32_t n = 0; n < nchans; ++n) {
2105 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2106 if ((prop = node.property (buf)) != 0) {
2108 PBD::ID id2 (prop->value());
2110 if ((source = source_by_id (id2)) == 0) {
2111 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2112 return boost::shared_ptr<AudioRegion>();
2115 as = boost::dynamic_pointer_cast<AudioSource>(source);
2117 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2118 return boost::shared_ptr<AudioRegion>();
2120 master_sources.push_back (as);
2125 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2127 /* a final detail: this is the one and only place that we know how long missing files are */
2129 if (region->whole_file()) {
2130 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2131 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2133 sfp->set_length (region->length());
2138 if (!master_sources.empty()) {
2139 if (master_sources.size() != nchans) {
2140 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2142 region->set_master_sources (master_sources);
2150 catch (failed_constructor& err) {
2151 return boost::shared_ptr<AudioRegion>();
2155 boost::shared_ptr<MidiRegion>
2156 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2158 XMLProperty const * prop;
2159 boost::shared_ptr<Source> source;
2160 boost::shared_ptr<MidiSource> ms;
2163 if (node.name() != X_("Region")) {
2164 return boost::shared_ptr<MidiRegion>();
2167 if ((prop = node.property ("name")) == 0) {
2168 cerr << "no name for this region\n";
2172 if ((prop = node.property (X_("source-0"))) == 0) {
2173 if ((prop = node.property ("source")) == 0) {
2174 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2175 return boost::shared_ptr<MidiRegion>();
2179 PBD::ID s_id (prop->value());
2181 if ((source = source_by_id (s_id)) == 0) {
2182 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2183 return boost::shared_ptr<MidiRegion>();
2186 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2188 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2189 return boost::shared_ptr<MidiRegion>();
2192 sources.push_back (ms);
2195 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2196 /* a final detail: this is the one and only place that we know how long missing files are */
2198 if (region->whole_file()) {
2199 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2200 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2202 sfp->set_length (region->length());
2210 catch (failed_constructor& err) {
2211 return boost::shared_ptr<MidiRegion>();
2216 Session::get_sources_as_xml ()
2219 XMLNode* node = new XMLNode (X_("Sources"));
2220 Glib::Threads::Mutex::Lock lm (source_lock);
2222 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2223 node->add_child_nocopy (i->second->get_state());
2230 Session::reset_write_sources (bool mark_write_complete, bool force)
2232 boost::shared_ptr<RouteList> rl = routes.reader();
2233 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2234 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2236 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2237 tr->reset_write_sources(mark_write_complete, force);
2238 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2244 Session::load_sources (const XMLNode& node)
2247 XMLNodeConstIterator niter;
2248 /* don't need this but it stops some
2249 * versions of gcc complaining about
2250 * discarded return values.
2252 boost::shared_ptr<Source> source;
2254 nlist = node.children();
2257 std::map<std::string, std::string> relocation;
2259 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2260 #ifdef PLATFORM_WINDOWS
2264 XMLNode srcnode (**niter);
2265 bool try_replace_abspath = true;
2269 #ifdef PLATFORM_WINDOWS
2270 // do not show "insert media" popups (files embedded from removable media).
2271 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2273 if ((source = XMLSourceFactory (srcnode)) == 0) {
2274 error << _("Session: cannot create Source from XML description.") << endmsg;
2276 #ifdef PLATFORM_WINDOWS
2277 SetErrorMode(old_mode);
2280 } catch (MissingSource& err) {
2281 #ifdef PLATFORM_WINDOWS
2282 SetErrorMode(old_mode);
2285 /* try previous abs path replacements first */
2286 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2287 std::string dir = Glib::path_get_dirname (err.path);
2288 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2289 if (rl != relocation.end ()) {
2290 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2291 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2292 srcnode.set_property ("origin", newpath);
2293 try_replace_abspath = false;
2300 _missing_file_replacement = "";
2302 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2303 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2304 PROGRAM_NAME) << endmsg;
2308 if (!no_questions_about_missing_files) {
2309 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2314 switch (user_choice) {
2316 /* user added a new search location
2317 * or selected a new absolute path,
2319 if (Glib::path_is_absolute (err.path)) {
2320 if (!_missing_file_replacement.empty ()) {
2321 /* replace origin, in XML */
2322 std::string newpath = Glib::build_filename (
2323 _missing_file_replacement, Glib::path_get_basename (err.path));
2324 srcnode.set_property ("origin", newpath);
2325 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2326 _missing_file_replacement = "";
2333 /* user asked to quit the entire session load */
2337 no_questions_about_missing_files = true;
2341 no_questions_about_missing_files = true;
2348 case DataType::AUDIO:
2349 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2352 case DataType::MIDI:
2353 /* The MIDI file is actually missing so
2354 * just create a new one in the same
2355 * location. Do not announce its
2359 if (!Glib::path_is_absolute (err.path)) {
2360 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2362 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2367 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2368 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2369 /* reset ID to match the missing one */
2370 source->set_id (**niter);
2371 /* Now we can announce it */
2372 SourceFactory::SourceCreated (source);
2383 boost::shared_ptr<Source>
2384 Session::XMLSourceFactory (const XMLNode& node)
2386 if (node.name() != "Source") {
2387 return boost::shared_ptr<Source>();
2391 /* note: do peak building in another thread when loading session state */
2392 return SourceFactory::create (*this, node, true);
2395 catch (failed_constructor& err) {
2396 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2397 return boost::shared_ptr<Source>();
2402 Session::save_template (const string& template_name, const string& description, bool replace_existing)
2404 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2408 bool absolute_path = Glib::path_is_absolute (template_name);
2410 /* directory to put the template in */
2411 std::string template_dir_path;
2413 if (!absolute_path) {
2414 std::string user_template_dir(user_template_directory());
2416 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2417 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2418 user_template_dir, g_strerror (errno)) << endmsg;
2422 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2424 template_dir_path = template_name;
2427 if (!ARDOUR::Profile->get_trx()) {
2428 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2429 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2430 template_dir_path) << endmsg;
2434 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2435 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2436 template_dir_path, g_strerror (errno)) << endmsg;
2442 std::string template_file_path;
2444 if (ARDOUR::Profile->get_trx()) {
2445 template_file_path = template_name;
2447 if (absolute_path) {
2448 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2450 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2454 SessionSaveUnderway (); /* EMIT SIGNAL */
2459 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2460 root = &get_template ();
2463 root->remove_nodes_and_delete (X_("description"));
2465 if (!description.empty()) {
2466 XMLNode* desc = new XMLNode (X_("description"));
2467 XMLNode* desc_cont = new XMLNode (X_("content"), description);
2468 desc->add_child_nocopy (*desc_cont);
2470 root->add_child_nocopy (*desc);
2473 tree.set_root (root);
2475 if (!tree.write (template_file_path)) {
2476 error << _("template not saved") << endmsg;
2480 store_recent_templates (template_file_path);
2486 Session::refresh_disk_space ()
2488 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2490 Glib::Threads::Mutex::Lock lm (space_lock);
2492 /* get freespace on every FS that is part of the session path */
2494 _total_free_4k_blocks = 0;
2495 _total_free_4k_blocks_uncertain = false;
2497 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2498 #if defined(__NetBSD__)
2499 struct statvfs statfsbuf;
2501 statvfs (i->path.c_str(), &statfsbuf);
2503 struct statfs statfsbuf;
2505 statfs (i->path.c_str(), &statfsbuf);
2507 double const scale = statfsbuf.f_bsize / 4096.0;
2509 /* See if this filesystem is read-only */
2510 struct statvfs statvfsbuf;
2511 statvfs (i->path.c_str(), &statvfsbuf);
2513 /* f_bavail can be 0 if it is undefined for whatever
2514 filesystem we are looking at; Samba shares mounted
2515 via GVFS are an example of this.
2517 if (statfsbuf.f_bavail == 0) {
2518 /* block count unknown */
2520 i->blocks_unknown = true;
2521 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2522 /* read-only filesystem */
2524 i->blocks_unknown = false;
2526 /* read/write filesystem with known space */
2527 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2528 i->blocks_unknown = false;
2531 _total_free_4k_blocks += i->blocks;
2532 if (i->blocks_unknown) {
2533 _total_free_4k_blocks_uncertain = true;
2536 #elif defined PLATFORM_WINDOWS
2537 vector<string> scanned_volumes;
2538 vector<string>::iterator j;
2539 vector<space_and_path>::iterator i;
2540 DWORD nSectorsPerCluster, nBytesPerSector,
2541 nFreeClusters, nTotalClusters;
2545 _total_free_4k_blocks = 0;
2547 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2548 strncpy (disk_drive, (*i).path.c_str(), 3);
2552 volume_found = false;
2553 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2555 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2556 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2557 i->blocks = (uint32_t)(nFreeBytes / 4096);
2559 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2560 if (0 == j->compare(disk_drive)) {
2561 volume_found = true;
2566 if (!volume_found) {
2567 scanned_volumes.push_back(disk_drive);
2568 _total_free_4k_blocks += i->blocks;
2573 if (0 == _total_free_4k_blocks) {
2574 strncpy (disk_drive, path().c_str(), 3);
2577 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2579 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2580 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2581 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2588 Session::get_best_session_directory_for_new_audio ()
2590 vector<space_and_path>::iterator i;
2591 string result = _session_dir->root_path();
2593 /* handle common case without system calls */
2595 if (session_dirs.size() == 1) {
2599 /* OK, here's the algorithm we're following here:
2601 We want to select which directory to use for
2602 the next file source to be created. Ideally,
2603 we'd like to use a round-robin process so as to
2604 get maximum performance benefits from splitting
2605 the files across multiple disks.
2607 However, in situations without much diskspace, an
2608 RR approach may end up filling up a filesystem
2609 with new files while others still have space.
2610 Its therefore important to pay some attention to
2611 the freespace in the filesystem holding each
2612 directory as well. However, if we did that by
2613 itself, we'd keep creating new files in the file
2614 system with the most space until it was as full
2615 as all others, thus negating any performance
2616 benefits of this RAID-1 like approach.
2618 So, we use a user-configurable space threshold. If
2619 there are at least 2 filesystems with more than this
2620 much space available, we use RR selection between them.
2621 If not, then we pick the filesystem with the most space.
2623 This gets a good balance between the two
2627 refresh_disk_space ();
2629 int free_enough = 0;
2631 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2632 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2637 if (free_enough >= 2) {
2638 /* use RR selection process, ensuring that the one
2642 i = last_rr_session_dir;
2645 if (++i == session_dirs.end()) {
2646 i = session_dirs.begin();
2649 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2650 SessionDirectory sdir(i->path);
2651 if (sdir.create ()) {
2653 last_rr_session_dir = i;
2658 } while (i != last_rr_session_dir);
2662 /* pick FS with the most freespace (and that
2663 seems to actually work ...)
2666 vector<space_and_path> sorted;
2667 space_and_path_ascending_cmp cmp;
2669 sorted = session_dirs;
2670 sort (sorted.begin(), sorted.end(), cmp);
2672 for (i = sorted.begin(); i != sorted.end(); ++i) {
2673 SessionDirectory sdir(i->path);
2674 if (sdir.create ()) {
2676 last_rr_session_dir = i;
2686 Session::automation_dir () const
2688 return Glib::build_filename (_path, automation_dir_name);
2692 Session::analysis_dir () const
2694 return Glib::build_filename (_path, analysis_dir_name);
2698 Session::plugins_dir () const
2700 return Glib::build_filename (_path, plugins_dir_name);
2704 Session::externals_dir () const
2706 return Glib::build_filename (_path, externals_dir_name);
2710 Session::load_bundles (XMLNode const & node)
2712 XMLNodeList nlist = node.children();
2713 XMLNodeConstIterator niter;
2717 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2718 if ((*niter)->name() == "InputBundle") {
2719 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2720 } else if ((*niter)->name() == "OutputBundle") {
2721 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2723 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2732 Session::load_route_groups (const XMLNode& node, int version)
2734 XMLNodeList nlist = node.children();
2735 XMLNodeConstIterator niter;
2739 if (version >= 3000) {
2741 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2742 if ((*niter)->name() == "RouteGroup") {
2743 RouteGroup* rg = new RouteGroup (*this, "");
2744 add_route_group (rg);
2745 rg->set_state (**niter, version);
2749 } else if (version < 3000) {
2751 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2752 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2753 RouteGroup* rg = new RouteGroup (*this, "");
2754 add_route_group (rg);
2755 rg->set_state (**niter, version);
2764 state_file_filter (const string &str, void* /*arg*/)
2766 return (str.length() > strlen(statefile_suffix) &&
2767 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2771 remove_end(string state)
2773 string statename(state);
2775 string::size_type start,end;
2776 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2777 statename = statename.substr (start+1);
2780 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2781 end = statename.length();
2784 return string(statename.substr (0, end));
2788 Session::possible_states (string path)
2790 vector<string> states;
2791 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2793 transform(states.begin(), states.end(), states.begin(), remove_end);
2795 sort (states.begin(), states.end());
2801 Session::possible_states () const
2803 return possible_states(_path);
2807 Session::new_route_group (const std::string& name)
2809 RouteGroup* rg = NULL;
2811 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2812 if ((*i)->name () == name) {
2819 rg = new RouteGroup (*this, name);
2820 add_route_group (rg);
2826 Session::add_route_group (RouteGroup* g)
2828 _route_groups.push_back (g);
2829 route_group_added (g); /* EMIT SIGNAL */
2831 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2832 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2833 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2839 Session::remove_route_group (RouteGroup& rg)
2841 list<RouteGroup*>::iterator i;
2843 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2844 _route_groups.erase (i);
2847 route_group_removed (); /* EMIT SIGNAL */
2851 /** Set a new order for our route groups, without adding or removing any.
2852 * @param groups Route group list in the new order.
2855 Session::reorder_route_groups (list<RouteGroup*> groups)
2857 _route_groups = groups;
2859 route_groups_reordered (); /* EMIT SIGNAL */
2865 Session::route_group_by_name (string name)
2867 list<RouteGroup *>::iterator i;
2869 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2870 if ((*i)->name() == name) {
2878 Session::all_route_group() const
2880 return *_all_route_group;
2884 Session::add_commands (vector<Command*> const & cmds)
2886 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2892 Session::add_command (Command* const cmd)
2894 assert (_current_trans);
2895 DEBUG_UNDO_HISTORY (
2896 string_compose ("Current Undo Transaction %1, adding command: %2",
2897 _current_trans->name (),
2899 _current_trans->add_command (cmd);
2902 PBD::StatefulDiffCommand*
2903 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2905 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2911 Session::begin_reversible_command (const string& name)
2913 begin_reversible_command (g_quark_from_string (name.c_str ()));
2916 /** Begin a reversible command using a GQuark to identify it.
2917 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2918 * but there must be as many begin...()s as there are commit...()s.
2921 Session::begin_reversible_command (GQuark q)
2923 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2924 to hold all the commands that are committed. This keeps the order of
2925 commands correct in the history.
2928 if (_current_trans == 0) {
2929 DEBUG_UNDO_HISTORY (string_compose (
2930 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2932 /* start a new transaction */
2933 assert (_current_trans_quarks.empty ());
2934 _current_trans = new UndoTransaction();
2935 _current_trans->set_name (g_quark_to_string (q));
2937 DEBUG_UNDO_HISTORY (
2938 string_compose ("Begin Reversible Command, current transaction: %1",
2939 _current_trans->name ()));
2942 _current_trans_quarks.push_front (q);
2946 Session::abort_reversible_command ()
2948 if (_current_trans != 0) {
2949 DEBUG_UNDO_HISTORY (
2950 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2951 _current_trans->clear();
2952 delete _current_trans;
2954 _current_trans_quarks.clear();
2959 Session::commit_reversible_command (Command *cmd)
2961 assert (_current_trans);
2962 assert (!_current_trans_quarks.empty ());
2967 DEBUG_UNDO_HISTORY (
2968 string_compose ("Current Undo Transaction %1, adding command: %2",
2969 _current_trans->name (),
2971 _current_trans->add_command (cmd);
2974 DEBUG_UNDO_HISTORY (
2975 string_compose ("Commit Reversible Command, current transaction: %1",
2976 _current_trans->name ()));
2978 _current_trans_quarks.pop_front ();
2980 if (!_current_trans_quarks.empty ()) {
2981 DEBUG_UNDO_HISTORY (
2982 string_compose ("Commit Reversible Command, transaction is not "
2983 "top-level, current transaction: %1",
2984 _current_trans->name ()));
2985 /* the transaction we're committing is not the top-level one */
2989 if (_current_trans->empty()) {
2990 /* no commands were added to the transaction, so just get rid of it */
2991 DEBUG_UNDO_HISTORY (
2992 string_compose ("Commit Reversible Command, No commands were "
2993 "added to current transaction: %1",
2994 _current_trans->name ()));
2995 delete _current_trans;
3000 gettimeofday (&now, 0);
3001 _current_trans->set_timestamp (now);
3003 _history.add (_current_trans);
3008 accept_all_audio_files (const string& path, void* /*arg*/)
3010 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3014 if (!AudioFileSource::safe_audio_file_extension (path)) {
3022 accept_all_midi_files (const string& path, void* /*arg*/)
3024 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3028 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
3029 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
3030 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
3034 accept_all_state_files (const string& path, void* /*arg*/)
3036 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
3040 std::string const statefile_ext (statefile_suffix);
3041 if (path.length() >= statefile_ext.length()) {
3042 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
3049 Session::find_all_sources (string path, set<string>& result)
3054 if (!tree.read (path)) {
3058 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
3063 XMLNodeConstIterator niter;
3065 nlist = node->children();
3069 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
3071 XMLProperty const * prop;
3073 if ((prop = (*niter)->property (X_("type"))) == 0) {
3077 DataType type (prop->value());
3079 if ((prop = (*niter)->property (X_("name"))) == 0) {
3083 if (Glib::path_is_absolute (prop->value())) {
3084 /* external file, ignore */
3092 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
3093 result.insert (found_path);
3101 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3103 vector<string> state_files;
3105 string this_snapshot_path;
3111 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3112 ripped = ripped.substr (0, ripped.length() - 1);
3115 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3117 if (state_files.empty()) {
3122 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3123 this_snapshot_path += statefile_suffix;
3125 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3127 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3129 if (exclude_this_snapshot && *i == this_snapshot_path) {
3130 cerr << "\texcluded\n";
3135 if (find_all_sources (*i, result) < 0) {
3143 struct RegionCounter {
3144 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3145 AudioSourceList::iterator iter;
3146 boost::shared_ptr<Region> region;
3149 RegionCounter() : count (0) {}
3153 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3155 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3156 return r.get_value_or (1);
3160 Session::cleanup_regions ()
3162 bool removed = false;
3163 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3165 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3167 uint32_t used = playlists->region_use_count (i->second);
3169 if (used == 0 && !i->second->automatic ()) {
3170 boost::weak_ptr<Region> w = i->second;
3173 RegionFactory::map_remove (w);
3180 // re-check to remove parent references of compound regions
3181 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3182 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3186 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3187 if (0 == playlists->region_use_count (i->second)) {
3188 boost::weak_ptr<Region> w = i->second;
3190 RegionFactory::map_remove (w);
3197 /* dump the history list */
3204 Session::can_cleanup_peakfiles () const
3206 if (deletion_in_progress()) {
3209 if (!_writable || (_state_of_the_state & CannotSave)) {
3210 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3213 if (record_status() == Recording) {
3214 error << _("Cannot cleanup peak-files while recording") << endmsg;
3221 Session::cleanup_peakfiles ()
3223 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3228 assert (can_cleanup_peakfiles ());
3229 assert (!peaks_cleanup_in_progres());
3231 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3233 int timeout = 5000; // 5 seconds
3234 while (!SourceFactory::files_with_peaks.empty()) {
3235 Glib::usleep (1000);
3236 if (--timeout < 0) {
3237 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3238 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3243 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3244 boost::shared_ptr<AudioSource> as;
3245 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3246 as->close_peakfile();
3250 PBD::clear_directory (session_directory().peak_path());
3252 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3254 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3255 boost::shared_ptr<AudioSource> as;
3256 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3257 SourceFactory::setup_peakfile(as, true);
3264 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3266 pl->deep_sources (*all_sources);
3270 Session::cleanup_sources (CleanupReport& rep)
3272 // FIXME: needs adaptation to midi
3274 vector<boost::shared_ptr<Source> > dead_sources;
3277 vector<string> candidates;
3278 vector<string> unused;
3279 set<string> sources_used_by_all_snapshots;
3286 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3288 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3290 /* this is mostly for windows which doesn't allow file
3291 * renaming if the file is in use. But we don't special
3292 * case it because we need to know if this causes
3293 * problems, and the easiest way to notice that is to
3294 * keep it in place for all platforms.
3297 request_stop (false);
3299 _butler->wait_until_finished ();
3301 /* consider deleting all unused playlists */
3303 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3308 /* sync the "all regions" property of each playlist with its current state */
3310 playlists->sync_all_regions_with_regions ();
3312 /* find all un-used sources */
3317 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3319 SourceMap::iterator tmp;
3324 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3328 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3329 dead_sources.push_back (i->second);
3330 i->second->drop_references ();
3336 /* build a list of all the possible audio directories for the session */
3338 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3339 SessionDirectory sdir ((*i).path);
3340 asp += sdir.sound_path();
3342 audio_path += asp.to_string();
3345 /* build a list of all the possible midi directories for the session */
3347 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3348 SessionDirectory sdir ((*i).path);
3349 msp += sdir.midi_path();
3351 midi_path += msp.to_string();
3353 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3354 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3356 /* add sources from all other snapshots as "used", but don't use this
3357 snapshot because the state file on disk still references sources we
3358 may have already dropped.
3361 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3363 /* Although the region factory has a list of all regions ever created
3364 * for this session, we're only interested in regions actually in
3365 * playlists right now. So merge all playlist regions lists together.
3367 * This will include the playlists used within compound regions.
3370 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3372 /* add our current source list
3375 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3376 boost::shared_ptr<FileSource> fs;
3377 SourceMap::iterator tmp = i;
3380 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3386 /* this is mostly for windows which doesn't allow file
3387 * renaming if the file is in use. But we do not special
3388 * case it because we need to know if this causes
3389 * problems, and the easiest way to notice that is to
3390 * keep it in place for all platforms.
3395 if (!fs->is_stub()) {
3397 /* Note that we're checking a list of all
3398 * sources across all snapshots with the list
3399 * of sources used by this snapshot.
3402 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3403 /* this source is in use by this snapshot */
3404 sources_used_by_all_snapshots.insert (fs->path());
3405 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3407 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3408 /* this source is NOT in use by this snapshot */
3410 /* remove all related regions from RegionFactory master list */
3412 RegionFactory::remove_regions_using_source (i->second);
3414 /* remove from our current source list
3415 * also. We may not remove it from
3416 * disk, because it may be used by
3417 * other snapshots, but it isn't used inside this
3418 * snapshot anymore, so we don't need a
3429 /* now check each candidate source to see if it exists in the list of
3430 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3433 cerr << "Candidates: " << candidates.size() << endl;
3434 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3436 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3441 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3443 tmppath1 = canonical_path (spath);
3444 tmppath2 = canonical_path ((*i));
3446 cerr << "\t => " << tmppath2 << endl;
3448 if (tmppath1 == tmppath2) {
3455 unused.push_back (spath);
3459 cerr << "Actually unused: " << unused.size() << endl;
3461 if (unused.empty()) {
3467 /* now try to move all unused files into the "dead" directory(ies) */
3469 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3474 /* don't move the file across filesystems, just
3475 * stick it in the `dead_dir_name' directory
3476 * on whichever filesystem it was already on.
3479 if ((*x).find ("/sounds/") != string::npos) {
3481 /* old school, go up 1 level */
3483 newpath = Glib::path_get_dirname (*x); // "sounds"
3484 newpath = Glib::path_get_dirname (newpath); // "session-name"
3488 /* new school, go up 4 levels */
3490 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3491 newpath = Glib::path_get_dirname (newpath); // "session-name"
3492 newpath = Glib::path_get_dirname (newpath); // "interchange"
3493 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3496 newpath = Glib::build_filename (newpath, dead_dir_name);
3498 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3499 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3503 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3505 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3507 /* the new path already exists, try versioning */
3509 char buf[PATH_MAX+1];
3513 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3516 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3517 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3521 if (version == 999) {
3522 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3526 newpath = newpath_v;
3531 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3532 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3533 newpath, g_strerror (errno)) << endmsg;
3537 /* see if there an easy to find peakfile for this file, and remove it. */
3539 string base = Glib::path_get_basename (*x);
3540 base += "%A"; /* this is what we add for the channel suffix of all native files,
3541 * or for the first channel of embedded files. it will miss
3542 * some peakfiles for other channels
3544 string peakpath = construct_peak_filepath (base);
3546 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3547 if (::g_unlink (peakpath.c_str ()) != 0) {
3548 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3549 g_strerror (errno)) << endmsg;
3550 /* try to back out */
3551 ::g_rename (newpath.c_str (), _path.c_str ());
3556 rep.paths.push_back (*x);
3557 rep.space += statbuf.st_size;
3560 /* dump the history list */
3564 /* save state so we don't end up a session file
3565 * referring to non-existent sources.
3572 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3578 Session::cleanup_trash_sources (CleanupReport& rep)
3580 // FIXME: needs adaptation for MIDI
3582 vector<space_and_path>::iterator i;
3588 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3590 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3592 clear_directory (dead_dir, &rep.space, &rep.paths);
3599 Session::set_dirty ()
3601 /* return early if there's nothing to do */
3606 /* never mark session dirty during loading */
3607 if (_state_of_the_state & Loading) {
3611 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3612 DirtyChanged(); /* EMIT SIGNAL */
3616 Session::set_clean ()
3618 bool was_dirty = dirty();
3620 _state_of_the_state = Clean;
3623 DirtyChanged(); /* EMIT SIGNAL */
3628 Session::set_deletion_in_progress ()
3630 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3634 Session::clear_deletion_in_progress ()
3636 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3640 Session::add_controllable (boost::shared_ptr<Controllable> c)
3642 /* this adds a controllable to the list managed by the Session.
3643 this is a subset of those managed by the Controllable class
3644 itself, and represents the only ones whose state will be saved
3645 as part of the session.
3648 Glib::Threads::Mutex::Lock lm (controllables_lock);
3649 controllables.insert (c);
3652 struct null_deleter { void operator()(void const *) const {} };
3655 Session::remove_controllable (Controllable* c)
3657 if (_state_of_the_state & Deletion) {
3661 Glib::Threads::Mutex::Lock lm (controllables_lock);
3663 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3665 if (x != controllables.end()) {
3666 controllables.erase (x);
3670 boost::shared_ptr<Controllable>
3671 Session::controllable_by_id (const PBD::ID& id)
3673 Glib::Threads::Mutex::Lock lm (controllables_lock);
3675 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3676 if ((*i)->id() == id) {
3681 return boost::shared_ptr<Controllable>();
3684 boost::shared_ptr<AutomationControl>
3685 Session::automation_control_by_id (const PBD::ID& id)
3687 return boost::dynamic_pointer_cast<AutomationControl> (controllable_by_id (id));
3690 boost::shared_ptr<Controllable>
3691 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3693 boost::shared_ptr<Controllable> c;
3694 boost::shared_ptr<Stripable> s;
3695 boost::shared_ptr<Route> r;
3697 switch (desc.top_level_type()) {
3698 case ControllableDescriptor::NamedRoute:
3700 std::string str = desc.top_level_name();
3702 if (str == "Master" || str == "master") {
3704 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3706 } else if (str == "auditioner") {
3709 s = route_by_name (desc.top_level_name());
3715 case ControllableDescriptor::PresentationOrderRoute:
3716 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3719 case ControllableDescriptor::PresentationOrderTrack:
3720 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3723 case ControllableDescriptor::PresentationOrderBus:
3724 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3727 case ControllableDescriptor::PresentationOrderVCA:
3728 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3731 case ControllableDescriptor::SelectionCount:
3732 s = route_by_selected_count (desc.selection_id());
3740 r = boost::dynamic_pointer_cast<Route> (s);
3742 switch (desc.subtype()) {
3743 case ControllableDescriptor::Gain:
3744 c = s->gain_control ();
3747 case ControllableDescriptor::Trim:
3748 c = s->trim_control ();
3751 case ControllableDescriptor::Solo:
3752 c = s->solo_control();
3755 case ControllableDescriptor::Mute:
3756 c = s->mute_control();
3759 case ControllableDescriptor::Recenable:
3760 c = s->rec_enable_control ();
3763 case ControllableDescriptor::PanDirection:
3764 c = s->pan_azimuth_control();
3767 case ControllableDescriptor::PanWidth:
3768 c = s->pan_width_control();
3771 case ControllableDescriptor::PanElevation:
3772 c = s->pan_elevation_control();
3775 case ControllableDescriptor::Balance:
3776 /* XXX simple pan control */
3779 case ControllableDescriptor::PluginParameter:
3781 uint32_t plugin = desc.target (0);
3782 uint32_t parameter_index = desc.target (1);
3784 /* revert to zero based counting */
3790 if (parameter_index > 0) {
3798 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3801 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3802 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3807 case ControllableDescriptor::SendGain: {
3808 uint32_t send = desc.target (0);
3815 c = r->send_level_controllable (send);
3820 /* relax and return a null pointer */
3828 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3831 Stateful::add_instant_xml (node, _path);
3834 if (write_to_config) {
3835 Config->add_instant_xml (node);
3840 Session::instant_xml (const string& node_name)
3842 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3843 if (get_disable_all_loaded_plugins ()) {
3847 return Stateful::instant_xml (node_name, _path);
3851 Session::save_history (string snapshot_name)
3859 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3860 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3864 if (snapshot_name.empty()) {
3865 snapshot_name = _current_snapshot_name;
3868 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3869 const string backup_filename = history_filename + backup_suffix;
3870 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3871 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3873 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3874 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3875 error << _("could not backup old history file, current history not saved") << endmsg;
3880 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3882 if (!tree.write (xml_path))
3884 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3886 if (g_remove (xml_path.c_str()) != 0) {
3887 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3888 xml_path, g_strerror (errno)) << endmsg;
3890 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3891 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3892 backup_path, g_strerror (errno)) << endmsg;
3902 Session::restore_history (string snapshot_name)
3906 if (snapshot_name.empty()) {
3907 snapshot_name = _current_snapshot_name;
3910 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3911 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3913 info << "Loading history from " << xml_path << endmsg;
3915 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3916 info << string_compose (_("%1: no history file \"%2\" for this session."),
3917 _name, xml_path) << endmsg;
3921 if (!tree.read (xml_path)) {
3922 error << string_compose (_("Could not understand session history file \"%1\""),
3923 xml_path) << endmsg;
3930 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3933 UndoTransaction* ut = new UndoTransaction ();
3939 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3940 !t->get_property ("tv-usec", tv_usec)) {
3944 ut->set_name (name);
3948 tv.tv_usec = tv_usec;
3949 ut->set_timestamp(tv);
3951 for (XMLNodeConstIterator child_it = t->children().begin();
3952 child_it != t->children().end(); child_it++)
3954 XMLNode *n = *child_it;
3957 if (n->name() == "MementoCommand" ||
3958 n->name() == "MementoUndoCommand" ||
3959 n->name() == "MementoRedoCommand") {
3961 if ((c = memento_command_factory(n))) {
3965 } else if (n->name() == "NoteDiffCommand") {
3966 PBD::ID id (n->property("midi-source")->value());
3967 boost::shared_ptr<MidiSource> midi_source =
3968 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3970 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3972 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3975 } else if (n->name() == "SysExDiffCommand") {
3977 PBD::ID id (n->property("midi-source")->value());
3978 boost::shared_ptr<MidiSource> midi_source =
3979 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3981 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3983 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3986 } else if (n->name() == "PatchChangeDiffCommand") {
3988 PBD::ID id (n->property("midi-source")->value());
3989 boost::shared_ptr<MidiSource> midi_source =
3990 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3992 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3994 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3997 } else if (n->name() == "StatefulDiffCommand") {
3998 if ((c = stateful_diff_command_factory (n))) {
3999 ut->add_command (c);
4002 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
4013 Session::config_changed (std::string p, bool ours)
4019 if (p == "seamless-loop") {
4021 } else if (p == "rf-speed") {
4023 } else if (p == "auto-loop") {
4025 } else if (p == "session-monitoring") {
4027 } else if (p == "auto-input") {
4029 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
4030 /* auto-input only makes a difference if we're rolling */
4031 set_track_monitor_input_status (!config.get_auto_input());
4034 } else if (p == "punch-in") {
4038 if ((location = _locations->auto_punch_location()) != 0) {
4040 if (config.get_punch_in ()) {
4041 replace_event (SessionEvent::PunchIn, location->start());
4043 remove_event (location->start(), SessionEvent::PunchIn);
4047 } else if (p == "punch-out") {
4051 if ((location = _locations->auto_punch_location()) != 0) {
4053 if (config.get_punch_out()) {
4054 replace_event (SessionEvent::PunchOut, location->end());
4056 clear_events (SessionEvent::PunchOut);
4060 } else if (p == "edit-mode") {
4062 Glib::Threads::Mutex::Lock lm (playlists->lock);
4064 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
4065 (*i)->set_edit_mode (Config->get_edit_mode ());
4068 } else if (p == "use-video-sync") {
4070 waiting_for_sync_offset = config.get_use_video_sync();
4072 } else if (p == "mmc-control") {
4074 //poke_midi_thread ();
4076 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
4078 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
4080 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
4082 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
4084 } else if (p == "midi-control") {
4086 //poke_midi_thread ();
4088 } else if (p == "raid-path") {
4090 setup_raid_path (config.get_raid_path());
4092 } else if (p == "timecode-format") {
4096 } else if (p == "video-pullup") {
4100 } else if (p == "seamless-loop") {
4102 if (play_loop && transport_rolling()) {
4103 // to reset diskstreams etc
4104 request_play_loop (true);
4107 } else if (p == "rf-speed") {
4109 cumulative_rf_motion = 0;
4112 } else if (p == "click-sound") {
4114 setup_click_sounds (1);
4116 } else if (p == "click-emphasis-sound") {
4118 setup_click_sounds (-1);
4120 } else if (p == "clicking") {
4122 if (Config->get_clicking()) {
4123 if (_click_io && click_data) { // don't require emphasis data
4130 } else if (p == "click-record-only") {
4132 _click_rec_only = Config->get_click_record_only();
4134 } else if (p == "click-gain") {
4137 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4140 } else if (p == "send-mtc") {
4142 if (Config->get_send_mtc ()) {
4143 /* mark us ready to send */
4144 next_quarter_frame_to_send = 0;
4147 } else if (p == "send-mmc") {
4149 _mmc->enable_send (Config->get_send_mmc ());
4151 } else if (p == "jack-time-master") {
4153 engine().reset_timebase ();
4155 } else if (p == "native-file-header-format") {
4157 if (!first_file_header_format_reset) {
4158 reset_native_file_format ();
4161 first_file_header_format_reset = false;
4163 } else if (p == "native-file-data-format") {
4165 if (!first_file_data_format_reset) {
4166 reset_native_file_format ();
4169 first_file_data_format_reset = false;
4171 } else if (p == "external-sync") {
4172 if (!config.get_external_sync()) {
4173 drop_sync_source ();
4175 switch_to_sync_source (Config->get_sync_source());
4177 } else if (p == "denormal-model") {
4179 } else if (p == "history-depth") {
4180 set_history_depth (Config->get_history_depth());
4181 } else if (p == "remote-model") {
4182 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4185 } else if (p == "initial-program-change") {
4187 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4190 buf[0] = MIDI::program; // channel zero by default
4191 buf[1] = (Config->get_initial_program_change() & 0x7f);
4193 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4195 } else if (p == "solo-mute-override") {
4196 // catch_up_on_solo_mute_override ();
4197 } else if (p == "listen-position" || p == "pfl-position") {
4198 listen_position_changed ();
4199 } else if (p == "solo-control-is-listen-control") {
4200 solo_control_mode_changed ();
4201 } else if (p == "solo-mute-gain") {
4202 _solo_cut_control->Changed (true, Controllable::NoGroup);
4203 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4204 last_timecode_valid = false;
4205 } else if (p == "playback-buffer-seconds") {
4206 AudioSource::allocate_working_buffers (frame_rate());
4207 } else if (p == "ltc-source-port") {
4208 reconnect_ltc_input ();
4209 } else if (p == "ltc-sink-port") {
4210 reconnect_ltc_output ();
4211 } else if (p == "timecode-generator-offset") {
4212 ltc_tx_parse_offset();
4213 } else if (p == "auto-return-target-list") {
4214 follow_playhead_priority ();
4221 Session::set_history_depth (uint32_t d)
4223 _history.set_depth (d);
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::parse_stateful_loading_version (const std::string& version)
4522 if (version.empty ()) {
4523 /* no version implies very old version of Ardour */
4527 if (version.find ('.') != string::npos) {
4528 /* old school version format */
4529 if (version[0] == '2') {
4535 return string_to<int32_t>(version);
4540 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4542 bool found_sr = false;
4543 bool found_data_format = false;
4544 std::string version;
4545 program_version = "";
4547 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4551 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4555 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4558 xmlFreeParserCtxt(ctxt);
4562 xmlNodePtr node = xmlDocGetRootElement(doc);
4565 xmlFreeParserCtxt(ctxt);
4570 /* sample rate & version*/
4573 for (attr = node->properties; attr; attr = attr->next) {
4574 if (!strcmp ((const char*)attr->name, "version") && attr->children) {
4575 version = std::string ((char*)attr->children->content);
4577 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4578 sample_rate = atoi ((char*)attr->children->content);
4583 if ((parse_stateful_loading_version(version) / 1000L) > (CURRENT_SESSION_FILE_VERSION / 1000L)) {
4587 node = node->children;
4588 while (node != NULL) {
4589 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4590 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4592 program_version = string ((const char*)val);
4593 size_t sep = program_version.find_first_of("-");
4594 if (sep != string::npos) {
4595 program_version = program_version.substr (0, sep);
4600 if (strcmp((const char*) node->name, "Config")) {
4604 for (node = node->children; node; node = node->next) {
4605 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4606 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4608 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4611 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4613 found_data_format = true;
4614 } catch (PBD::unknown_enumeration& e) {}
4624 xmlFreeParserCtxt(ctxt);
4627 return (found_sr && found_data_format) ? 0 : 1;
4631 Session::get_snapshot_from_instant (const std::string& session_dir)
4633 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4635 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4640 if (!tree.read (instant_xml_path)) {
4644 XMLProperty const * prop;
4645 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4646 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4647 return prop->value();
4653 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4654 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4657 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4661 SourcePathMap source_path_map;
4663 boost::shared_ptr<AudioFileSource> afs;
4668 Glib::Threads::Mutex::Lock lm (source_lock);
4670 cerr << " total sources = " << sources.size();
4672 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4673 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4679 if (fs->within_session()) {
4683 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4684 source_path_map[fs->path()].push_back (fs);
4686 SeveralFileSources v;
4688 source_path_map.insert (make_pair (fs->path(), v));
4694 cerr << " fsources = " << total << endl;
4696 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4698 /* tell caller where we are */
4700 string old_path = i->first;
4702 callback (n, total, old_path);
4704 cerr << old_path << endl;
4708 switch (i->second.front()->type()) {
4709 case DataType::AUDIO:
4710 new_path = new_audio_source_path_for_embedded (old_path);
4713 case DataType::MIDI:
4714 /* XXX not implemented yet */
4718 if (new_path.empty()) {
4722 cerr << "Move " << old_path << " => " << new_path << endl;
4724 if (!copy_file (old_path, new_path)) {
4725 cerr << "failed !\n";
4729 /* make sure we stop looking in the external
4730 dir/folder. Remember, this is an all-or-nothing
4731 operations, it doesn't merge just some files.
4733 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4735 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4736 (*f)->set_path (new_path);
4741 save_state ("", false, false);
4747 bool accept_all_files (string const &, void *)
4753 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4755 /* 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.
4760 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4762 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4764 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4766 v.push_back (new_session_folder); /* full path */
4767 v.push_back (interchange_dir_name);
4768 v.push_back (new_session_path); /* just one directory/folder */
4769 v.push_back (typedir);
4770 v.push_back (Glib::path_get_basename (old_path));
4772 return Glib::build_filename (v);
4776 Session::save_as (SaveAs& saveas)
4778 vector<string> files;
4779 string current_folder = Glib::path_get_dirname (_path);
4780 string new_folder = legalize_for_path (saveas.new_name);
4781 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4782 int64_t total_bytes = 0;
4786 int32_t internal_file_cnt = 0;
4788 vector<string> do_not_copy_extensions;
4789 do_not_copy_extensions.push_back (statefile_suffix);
4790 do_not_copy_extensions.push_back (pending_suffix);
4791 do_not_copy_extensions.push_back (backup_suffix);
4792 do_not_copy_extensions.push_back (temp_suffix);
4793 do_not_copy_extensions.push_back (history_suffix);
4795 /* get total size */
4797 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4799 /* need to clear this because
4800 * find_files_matching_filter() is cumulative
4805 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4807 all += files.size();
4809 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4811 g_stat ((*i).c_str(), &gsb);
4812 total_bytes += gsb.st_size;
4816 /* save old values so we can switch back if we are not switching to the new session */
4818 string old_path = _path;
4819 string old_name = _name;
4820 string old_snapshot = _current_snapshot_name;
4821 string old_sd = _session_dir->root_path();
4822 vector<string> old_search_path[DataType::num_types];
4823 string old_config_search_path[DataType::num_types];
4825 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4826 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4827 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4828 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4830 /* switch session directory */
4832 (*_session_dir) = to_dir;
4834 /* create new tree */
4836 if (!_session_dir->create()) {
4837 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4842 /* copy all relevant files. Find each location in session_dirs,
4843 * and copy files from there to target.
4846 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4848 /* need to clear this because
4849 * find_files_matching_filter() is cumulative
4854 const size_t prefix_len = (*sd).path.size();
4856 /* Work just on the files within this session dir */
4858 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4860 /* add dir separator to protect against collisions with
4861 * track names (e.g. track named "audiofiles" or
4865 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4866 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4867 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4869 /* copy all the files. Handling is different for media files
4870 than others because of the *silly* subtree we have below the interchange
4871 folder. That really was a bad idea, but I'm not fixing it as part of
4872 implementing ::save_as().
4875 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4877 std::string from = *i;
4880 string filename = Glib::path_get_basename (from);
4881 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4882 if (filename == ".DS_STORE") {
4887 if (from.find (audiofile_dir_string) != string::npos) {
4889 /* audio file: only copy if asked */
4891 if (saveas.include_media && saveas.copy_media) {
4893 string to = make_new_media_path (*i, to_dir, new_folder);
4895 info << "media file copying from " << from << " to " << to << endmsg;
4897 if (!copy_file (from, to)) {
4898 throw Glib::FileError (Glib::FileError::IO_ERROR,
4899 string_compose(_("\ncopying \"%1\" failed !"), from));
4903 /* we found media files inside the session folder */
4905 internal_file_cnt++;
4907 } else if (from.find (midifile_dir_string) != string::npos) {
4909 /* midi file: always copy unless
4910 * creating an empty new session
4913 if (saveas.include_media) {
4915 string to = make_new_media_path (*i, to_dir, new_folder);
4917 info << "media file copying from " << from << " to " << to << endmsg;
4919 if (!copy_file (from, to)) {
4920 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4924 /* we found media files inside the session folder */
4926 internal_file_cnt++;
4928 } else if (from.find (analysis_dir_string) != string::npos) {
4930 /* make sure analysis dir exists in
4931 * new session folder, but we're not
4932 * copying analysis files here, see
4936 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4941 /* normal non-media file. Don't copy state, history, etc.
4944 bool do_copy = true;
4946 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4947 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4948 /* end of filename matches extension, do not copy file */
4954 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4955 /* don't copy peakfiles if
4956 * we're not copying media
4962 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4964 info << "attempting to make directory/folder " << to << endmsg;
4966 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4967 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4970 info << "attempting to copy " << from << " to " << to << endmsg;
4972 if (!copy_file (from, to)) {
4973 throw Glib::FileError (Glib::FileError::IO_ERROR,
4974 string_compose(_("\ncopying \"%1\" failed !"), from));
4979 /* measure file size even if we're not going to copy so that our Progress
4980 signals are correct, since we included these do-not-copy files
4981 in the computation of the total size and file count.
4985 g_stat (from.c_str(), &gsb);
4986 copied += gsb.st_size;
4989 double fraction = (double) copied / total_bytes;
4991 bool keep_going = true;
4993 if (saveas.copy_media) {
4995 /* no need or expectation of this if
4996 * media is not being copied, because
4997 * it will be fast(ish).
5000 /* tell someone "X percent, file M of N"; M is one-based */
5002 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
5010 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
5016 /* copy optional folders, if any */
5018 string old = plugins_dir ();
5019 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5020 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5021 copy_files (old, newdir);
5024 old = externals_dir ();
5025 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5026 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5027 copy_files (old, newdir);
5030 old = automation_dir ();
5031 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5032 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
5033 copy_files (old, newdir);
5036 if (saveas.include_media) {
5038 if (saveas.copy_media) {
5039 #ifndef PLATFORM_WINDOWS
5040 /* There are problems with analysis files on
5041 * Windows, because they used a colon in their
5042 * names as late as 4.0. Colons are not legal
5043 * under Windows even if NTFS allows them.
5045 * This is a tricky problem to solve so for
5046 * just don't copy these files. They will be
5047 * regenerated as-needed anyway, subject to the
5048 * existing issue that the filenames will be
5049 * rejected by Windows, which is a separate
5050 * problem (though related).
5053 /* only needed if we are copying media, since the
5054 * analysis data refers to media data
5057 old = analysis_dir ();
5058 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
5059 string newdir = Glib::build_filename (to_dir, "analysis");
5060 copy_files (old, newdir);
5062 #endif /* PLATFORM_WINDOWS */
5067 set_snapshot_name (saveas.new_name);
5068 _name = saveas.new_name;
5070 if (saveas.include_media && !saveas.copy_media) {
5072 /* reset search paths of the new session (which we're pretending to be right now) to
5073 include the original session search path, so we can still find all audio.
5076 if (internal_file_cnt) {
5077 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
5078 ensure_search_path_includes (*s, DataType::AUDIO);
5079 cerr << "be sure to include " << *s << " for audio" << endl;
5082 /* we do not do this for MIDI because we copy
5083 all MIDI files if saveas.include_media is
5089 bool was_dirty = dirty ();
5091 save_default_options ();
5093 if (saveas.copy_media && saveas.copy_external) {
5094 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
5095 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
5099 saveas.final_session_folder_name = _path;
5101 store_recent_sessions (_name, _path);
5103 if (!saveas.switch_to) {
5105 /* save the new state */
5107 save_state ("", false, false, !saveas.include_media);
5109 /* switch back to the way things were */
5113 set_snapshot_name (old_snapshot);
5115 (*_session_dir) = old_sd;
5121 if (internal_file_cnt) {
5122 /* reset these to their original values */
5123 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5124 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5129 /* prune session dirs, and update disk space statistics
5134 session_dirs.clear ();
5135 session_dirs.push_back (sp);
5136 refresh_disk_space ();
5138 _writable = exists_and_writable (_path);
5140 /* ensure that all existing tracks reset their current capture source paths
5142 reset_write_sources (true, true);
5144 /* creating new write sources marks the session as
5145 dirty. If the new session is empty, then
5146 save_state() thinks we're saving a template and will
5147 not mark the session as clean. So do that here,
5148 before we save state.
5151 if (!saveas.include_media) {
5152 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5155 save_state ("", false, false, !saveas.include_media);
5157 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5158 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5161 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5162 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5168 if (fs->within_session()) {
5169 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5170 fs->set_path (newpath);
5175 } catch (Glib::FileError& e) {
5177 saveas.failure_message = e.what();
5179 /* recursively remove all the directories */
5181 remove_directory (to_dir);
5189 saveas.failure_message = _("unknown reason");
5191 /* recursively remove all the directories */
5193 remove_directory (to_dir);
5203 static void set_progress (Progress* p, size_t n, size_t t)
5205 p->set_progress (float (n) / float(t));
5209 Session::archive_session (const std::string& dest,
5210 const std::string& name,
5211 ArchiveEncode compress_audio,
5212 bool only_used_sources,
5215 if (dest.empty () || name.empty ()) {
5219 /* save current values */
5220 bool was_dirty = dirty ();
5221 string old_path = _path;
5222 string old_name = _name;
5223 string old_snapshot = _current_snapshot_name;
5224 string old_sd = _session_dir->root_path();
5225 string old_config_search_path[DataType::num_types];
5226 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5227 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5229 /* ensure that session-path is included in search-path */
5231 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5232 if ((*sd).path == old_path) {
5240 /* create temporary dir to save session to */
5241 #ifdef PLATFORM_WINDOWS
5242 char tmp[256] = "C:\\TEMP\\";
5243 GetTempPath (sizeof (tmp), tmp);
5245 char const* tmp = getenv("TMPDIR");
5250 if ((strlen (tmp) + 21) > 1024) {
5255 strcpy (tmptpl, tmp);
5256 strcat (tmptpl, "ardourarchive-XXXXXX");
5257 char* tmpdir = g_mkdtemp (tmptpl);
5263 std::string to_dir = std::string (tmpdir);
5265 /* switch session directory temporarily */
5266 (*_session_dir) = to_dir;
5268 if (!_session_dir->create()) {
5269 (*_session_dir) = old_sd;
5270 remove_directory (to_dir);
5274 /* prepare archive */
5275 string archive = Glib::build_filename (dest, name + ".tar.xz");
5277 PBD::ScopedConnectionList progress_connection;
5278 PBD::FileArchive ar (archive);
5280 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5283 /* collect files to archive */
5284 std::map<string,string> filemap;
5286 vector<string> do_not_copy_extensions;
5287 do_not_copy_extensions.push_back (statefile_suffix);
5288 do_not_copy_extensions.push_back (pending_suffix);
5289 do_not_copy_extensions.push_back (backup_suffix);
5290 do_not_copy_extensions.push_back (temp_suffix);
5291 do_not_copy_extensions.push_back (history_suffix);
5293 vector<string> blacklist_dirs;
5294 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5295 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5296 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5297 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5298 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5299 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5301 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5302 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5304 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5305 if (only_used_sources) {
5306 playlists->sync_all_regions_with_regions ();
5307 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5310 // collect audio sources for this session, calc total size for encoding
5311 // add option to only include *used* sources (see Session::cleanup_sources)
5312 size_t total_size = 0;
5314 Glib::Threads::Mutex::Lock lm (source_lock);
5315 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5316 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5317 if (!afs || afs->readable_length () == 0) {
5321 if (only_used_sources) {
5325 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5330 std::string from = afs->path();
5332 if (compress_audio != NO_ENCODE) {
5333 total_size += afs->readable_length ();
5335 if (afs->within_session()) {
5336 filemap[from] = make_new_media_path (from, name, name);
5338 filemap[from] = make_new_media_path (from, name, name);
5339 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5346 if (compress_audio != NO_ENCODE) {
5348 progress->set_progress (2); // set to "encoding"
5349 progress->set_progress (0);
5352 Glib::Threads::Mutex::Lock lm (source_lock);
5353 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5354 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5355 if (!afs || afs->readable_length () == 0) {
5359 if (only_used_sources) {
5363 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5368 orig_sources[afs] = afs->path();
5369 orig_gain[afs] = afs->gain();
5371 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5372 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5373 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5376 progress->descend ((float)afs->readable_length () / total_size);
5380 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5381 afs->replace_file (new_path);
5382 afs->set_gain (ns->gain(), true);
5385 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5389 progress->ascend ();
5395 progress->set_progress (-1); // set to "archiving"
5396 progress->set_progress (0);
5399 /* index files relevant for this session */
5400 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5401 vector<string> files;
5403 size_t prefix_len = (*sd).path.size();
5404 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5408 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5410 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5411 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5412 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5414 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5415 std::string from = *i;
5418 string filename = Glib::path_get_basename (from);
5419 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5420 if (filename == ".DS_STORE") {
5425 if (from.find (audiofile_dir_string) != string::npos) {
5427 } else if (from.find (midifile_dir_string) != string::npos) {
5428 filemap[from] = make_new_media_path (from, name, name);
5429 } else if (from.find (videofile_dir_string) != string::npos) {
5430 filemap[from] = make_new_media_path (from, name, name);
5432 bool do_copy = true;
5433 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5434 if (from.find (*v) != string::npos) {
5439 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5440 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5447 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5453 /* write session file */
5455 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5457 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5460 save_default_options ();
5462 size_t prefix_len = _path.size();
5463 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5467 /* collect session-state files */
5468 vector<string> files;
5469 do_not_copy_extensions.clear ();
5470 do_not_copy_extensions.push_back (history_suffix);
5472 blacklist_dirs.clear ();
5473 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5475 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5476 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5477 std::string from = *i;
5478 bool do_copy = true;
5479 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5480 if (from.find (*v) != string::npos) {
5485 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5486 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5492 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5496 /* restore original values */
5499 set_snapshot_name (old_snapshot);
5500 (*_session_dir) = old_sd;
5504 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5505 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5507 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5508 i->first->replace_file (i->second);
5510 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5511 i->first->set_gain (i->second, true);
5514 int rv = ar.create (filemap);
5515 remove_directory (to_dir);
5521 Session::undo (uint32_t n)
5523 if (actively_recording()) {
5531 Session::redo (uint32_t n)
5533 if (actively_recording()) {