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"
31 #include <cstdio> /* snprintf(3) ... grrr */
44 #include <sys/param.h>
45 #include <sys/mount.h>
48 #ifdef HAVE_SYS_STATVFS_H
49 #include <sys/statvfs.h>
53 #include <pbd/gstdio_compat.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/boost_debug.h"
67 #include "pbd/basename.h"
68 #include "pbd/controllable_descriptor.h"
69 #include "pbd/debug.h"
70 #include "pbd/enumwriter.h"
71 #include "pbd/error.h"
72 #include "pbd/file_utils.h"
73 #include "pbd/pathexpand.h"
74 #include "pbd/pthread_utils.h"
75 #include "pbd/stacktrace.h"
76 #include "pbd/convert.h"
77 #include "pbd/localtime_r.h"
79 #include "ardour/amp.h"
80 #include "ardour/async_midi_port.h"
81 #include "ardour/audio_diskstream.h"
82 #include "ardour/audio_track.h"
83 #include "ardour/audioengine.h"
84 #include "ardour/audiofilesource.h"
85 #include "ardour/audioregion.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/butler.h"
88 #include "ardour/control_protocol_manager.h"
89 #include "ardour/directory_names.h"
90 #include "ardour/filename_extensions.h"
91 #include "ardour/graph.h"
92 #include "ardour/location.h"
93 #include "ardour/midi_model.h"
94 #include "ardour/midi_patch_manager.h"
95 #include "ardour/midi_region.h"
96 #include "ardour/midi_scene_changer.h"
97 #include "ardour/midi_source.h"
98 #include "ardour/midi_track.h"
99 #include "ardour/pannable.h"
100 #include "ardour/playlist_factory.h"
101 #include "ardour/playlist_source.h"
102 #include "ardour/port.h"
103 #include "ardour/processor.h"
104 #include "ardour/profile.h"
105 #include "ardour/proxy_controllable.h"
106 #include "ardour/recent_sessions.h"
107 #include "ardour/region_factory.h"
108 #include "ardour/route_group.h"
109 #include "ardour/send.h"
110 #include "ardour/session.h"
111 #include "ardour/session_directory.h"
112 #include "ardour/session_metadata.h"
113 #include "ardour/session_playlists.h"
114 #include "ardour/session_state_utils.h"
115 #include "ardour/silentfilesource.h"
116 #include "ardour/sndfilesource.h"
117 #include "ardour/source_factory.h"
118 #include "ardour/speakers.h"
119 #include "ardour/template_utils.h"
120 #include "ardour/tempo.h"
121 #include "ardour/ticker.h"
122 #include "ardour/user_bundle.h"
124 #include "control_protocol/control_protocol.h"
130 using namespace ARDOUR;
133 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
136 Session::pre_engine_init (string fullpath)
138 if (fullpath.empty()) {
140 throw failed_constructor();
143 /* discover canonical fullpath */
145 _path = canonical_path(fullpath);
148 if (Profile->get_trx() ) {
149 // Waves TracksLive has a usecase of session replacement with a new one.
150 // We should check session state file (<session_name>.ardour) existance
151 // to determine if the session is new or not
153 string full_session_name = Glib::build_filename( fullpath, _name );
154 full_session_name += statefile_suffix;
156 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
158 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
161 /* finish initialization that can't be done in a normal C++ constructor
165 timerclear (&last_mmc_step);
166 g_atomic_int_set (&processing_prohibited, 0);
167 g_atomic_int_set (&_record_status, Disabled);
168 g_atomic_int_set (&_playback_load, 100);
169 g_atomic_int_set (&_capture_load, 100);
171 _all_route_group->set_active (true, this);
172 interpolation.add_channel_to (0, 0);
174 if (config.get_use_video_sync()) {
175 waiting_for_sync_offset = true;
177 waiting_for_sync_offset = false;
180 last_rr_session_dir = session_dirs.begin();
182 set_history_depth (Config->get_history_depth());
184 /* default: assume simple stereo speaker configuration */
186 _speakers->setup_default_speakers (2);
188 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
189 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
190 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
191 add_controllable (_solo_cut_control);
193 /* These are all static "per-class" signals */
195 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
196 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
197 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
198 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
199 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
201 /* stop IO objects from doing stuff until we're ready for them */
203 Delivery::disable_panners ();
204 IO::disable_connecting ();
208 Session::post_engine_init ()
210 BootMessage (_("Set block size and sample rate"));
212 set_block_size (_engine.samples_per_cycle());
213 set_frame_rate (_engine.sample_rate());
215 BootMessage (_("Using configuration"));
217 _midi_ports = new MidiPortManager;
219 MIDISceneChanger* msc;
221 _scene_changer = msc = new MIDISceneChanger (*this);
222 msc->set_input_port (scene_input_port());
223 msc->set_output_port (scene_out());
225 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
226 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
228 setup_midi_machine_control ();
230 if (_butler->start_thread()) {
234 if (start_midi_thread ()) {
238 setup_click_sounds (0);
239 setup_midi_control ();
241 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
242 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
245 /* tempo map requires sample rate knowledge */
248 _tempo_map = new TempoMap (_current_frame_rate);
249 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
251 /* MidiClock requires a tempo map */
253 midi_clock = new MidiClockTicker ();
254 midi_clock->set_session (this);
256 /* crossfades require sample rate knowledge */
258 SndFileSource::setup_standard_crossfades (*this, frame_rate());
259 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
261 AudioDiskstream::allocate_working_buffers();
262 refresh_disk_space ();
264 /* we're finally ready to call set_state() ... all objects have
265 * been created, the engine is running.
269 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
273 // set_state() will call setup_raid_path(), but if it's a new session we need
274 // to call setup_raid_path() here.
275 setup_raid_path (_path);
280 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
281 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
283 Config->map_parameters (ff);
284 config.map_parameters (ft);
285 _butler->map_parameters ();
287 /* Reset all panners */
289 Delivery::reset_panners ();
291 /* this will cause the CPM to instantiate any protocols that are in use
292 * (or mandatory), which will pass it this Session, and then call
293 * set_state() on each instantiated protocol to match stored state.
296 ControlProtocolManager::instance().set_session (this);
298 /* This must be done after the ControlProtocolManager set_session above,
299 as it will set states for ports which the ControlProtocolManager creates.
302 // XXX set state of MIDI::Port's
303 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
305 /* And this must be done after the MIDI::Manager::set_port_states as
306 * it will try to make connections whose details are loaded by set_port_states.
311 /* Let control protocols know that we are now all connected, so they
312 * could start talking to surfaces if they want to.
315 ControlProtocolManager::instance().midi_connectivity_established ();
317 if (_is_new && !no_auto_connect()) {
318 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
319 auto_connect_master_bus ();
322 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
324 /* update latencies */
326 initialize_latencies ();
328 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
329 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
330 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
332 } catch (AudioEngine::PortRegistrationFailure& err) {
333 /* handle this one in a different way than all others, so that its clear what happened */
334 error << err.what() << endmsg;
340 BootMessage (_("Reset Remote Controls"));
342 // send_full_time_code (0);
343 _engine.transport_locate (0);
345 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
346 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
348 MIDI::Name::MidiPatchManager::instance().set_session (this);
351 /* initial program change will be delivered later; see ::config_changed() */
353 _state_of_the_state = Clean;
355 Port::set_connecting_blocked (false);
357 DirtyChanged (); /* EMIT SIGNAL */
361 } else if (state_was_pending) {
363 remove_pending_capture_state ();
364 state_was_pending = false;
367 /* Now, finally, we can fill the playback buffers */
369 BootMessage (_("Filling playback buffers"));
371 boost::shared_ptr<RouteList> rl = routes.reader();
372 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
373 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
374 if (trk && !trk->hidden()) {
375 trk->seek (_transport_frame, true);
383 Session::session_loaded ()
387 _state_of_the_state = Clean;
389 DirtyChanged (); /* EMIT SIGNAL */
393 } else if (state_was_pending) {
395 remove_pending_capture_state ();
396 state_was_pending = false;
399 /* Now, finally, we can fill the playback buffers */
401 BootMessage (_("Filling playback buffers"));
402 force_locate (_transport_frame, false);
406 Session::raid_path () const
408 Searchpath raid_search_path;
410 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
411 raid_search_path += (*i).path;
414 return raid_search_path.to_string ();
418 Session::setup_raid_path (string path)
427 session_dirs.clear ();
429 Searchpath search_path(path);
430 Searchpath sound_search_path;
431 Searchpath midi_search_path;
433 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
435 sp.blocks = 0; // not needed
436 session_dirs.push_back (sp);
438 SessionDirectory sdir(sp.path);
440 sound_search_path += sdir.sound_path ();
441 midi_search_path += sdir.midi_path ();
444 // reset the round-robin soundfile path thingie
445 last_rr_session_dir = session_dirs.begin();
449 Session::path_is_within_session (const std::string& path)
451 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
452 if (PBD::path_is_within (i->path, path)) {
460 Session::ensure_subdirs ()
464 dir = session_directory().peak_path();
466 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
467 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
471 dir = session_directory().sound_path();
473 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
474 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
478 dir = session_directory().midi_path();
480 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
481 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
485 dir = session_directory().dead_path();
487 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
488 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
492 dir = session_directory().export_path();
494 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
495 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
499 dir = analysis_dir ();
501 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
502 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 dir = plugins_dir ();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = externals_dir ();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
523 /** @param session_template directory containing session template, or empty.
524 * Caller must not hold process lock.
527 Session::create (const string& session_template, BusProfile* bus_profile)
529 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
534 if (ensure_subdirs ()) {
538 _writable = exists_and_writable (_path);
540 if (!session_template.empty()) {
541 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
543 FILE* in = g_fopen (in_path.c_str(), "rb");
546 /* no need to call legalize_for_path() since the string
547 * in session_template is already a legal path name
549 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
551 FILE* out = g_fopen (out_path.c_str(), "wb");
555 stringstream new_session;
558 size_t charsRead = fread (buf, sizeof(char), 1024, in);
561 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
566 if (charsRead == 0) {
569 new_session.write (buf, charsRead);
573 string file_contents = new_session.str();
574 size_t writeSize = file_contents.length();
575 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
576 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
584 if (!ARDOUR::Profile->get_trx()) {
585 /* Copy plugin state files from template to new session */
586 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
587 copy_recurse (template_plugins, plugins_dir ());
593 error << string_compose (_("Could not open %1 for writing session template"), out_path)
600 error << string_compose (_("Could not open session template %1 for reading"), in_path)
607 if (Profile->get_trx()) {
609 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
610 Remember that this is a brand new session. Sessions
611 loaded from saved state will get this range from the saved state.
614 set_session_range_location (0, 0);
616 /* Initial loop location, from absolute zero, length 10 seconds */
618 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
619 _locations->add (loc, true);
620 set_auto_loop_location (loc);
623 _state_of_the_state = Clean;
625 /* set up Master Out and Control Out if necessary */
630 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
632 // Waves Tracks: always create master bus for Tracks
633 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
634 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
638 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
639 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
642 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
643 r->input()->ensure_io (count, false, this);
644 r->output()->ensure_io (count, false, this);
650 /* prohibit auto-connect to master, because there isn't one */
651 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
655 add_routes (rl, false, false, false);
658 // Waves Tracks: Skip this. Always use autoconnection for Tracks
659 if (!ARDOUR::Profile->get_trx()) {
661 /* this allows the user to override settings with an environment variable.
664 if (no_auto_connect()) {
665 bus_profile->input_ac = AutoConnectOption (0);
666 bus_profile->output_ac = AutoConnectOption (0);
669 Config->set_input_auto_connect (bus_profile->input_ac);
670 Config->set_output_auto_connect (bus_profile->output_ac);
674 if (Config->get_use_monitor_bus() && bus_profile) {
675 add_monitor_section ();
682 Session::maybe_write_autosave()
684 if (dirty() && record_status() != Recording) {
685 save_state("", true);
690 Session::remove_pending_capture_state ()
692 std::string pending_state_file_path(_session_dir->root_path());
694 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
696 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
698 if (g_remove (pending_state_file_path.c_str()) != 0) {
699 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
700 pending_state_file_path, g_strerror (errno)) << endmsg;
704 /** Rename a state file.
705 * @param old_name Old snapshot name.
706 * @param new_name New snapshot name.
709 Session::rename_state (string old_name, string new_name)
711 if (old_name == _current_snapshot_name || old_name == _name) {
712 /* refuse to rename the current snapshot or the "main" one */
716 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
717 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
719 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
720 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
722 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
723 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
724 old_name, new_name, g_strerror(errno)) << endmsg;
728 /** Remove a state file.
729 * @param snapshot_name Snapshot name.
732 Session::remove_state (string snapshot_name)
734 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
735 // refuse to remove the current snapshot or the "main" one
739 std::string xml_path(_session_dir->root_path());
741 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
743 if (!create_backup_file (xml_path)) {
744 // don't remove it if a backup can't be made
745 // create_backup_file will log the error.
750 if (g_remove (xml_path.c_str()) != 0) {
751 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
752 xml_path, g_strerror (errno)) << endmsg;
756 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
758 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
761 std::string xml_path(_session_dir->root_path());
763 /* prevent concurrent saves from different threads */
765 Glib::Threads::Mutex::Lock lm (save_state_lock);
767 if (!_writable || (_state_of_the_state & CannotSave)) {
771 if (g_atomic_int_get(&_suspend_save)) {
775 _save_queued = false;
777 if (!_engine.connected ()) {
778 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
784 /* tell sources we're saving first, in case they write out to a new file
785 * which should be saved with the state rather than the old one */
786 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
788 i->second->session_saved();
789 } catch (Evoral::SMF::FileError& e) {
790 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
794 SessionSaveUnderway (); /* EMIT SIGNAL */
797 tree.set_root (&get_template());
799 tree.set_root (&get_state());
802 if (snapshot_name.empty()) {
803 snapshot_name = _current_snapshot_name;
804 } else if (switch_to_snapshot) {
805 _current_snapshot_name = snapshot_name;
810 /* proper save: use statefile_suffix (.ardour in English) */
812 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
814 /* make a backup copy of the old file */
816 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
817 // create_backup_file will log the error
823 /* pending save: use pending_suffix (.pending in English) */
824 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
827 std::string tmp_path(_session_dir->root_path());
828 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
830 cerr << "actually writing state to " << tmp_path << endl;
832 if (!tree.write (tmp_path)) {
833 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
834 if (g_remove (tmp_path.c_str()) != 0) {
835 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
836 tmp_path, g_strerror (errno)) << endmsg;
842 cerr << "renaming state to " << xml_path << endl;
844 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
845 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
846 tmp_path, xml_path, g_strerror(errno)) << endmsg;
847 if (g_remove (tmp_path.c_str()) != 0) {
848 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
849 tmp_path, g_strerror (errno)) << endmsg;
857 save_history (snapshot_name);
859 bool was_dirty = dirty();
861 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
864 DirtyChanged (); /* EMIT SIGNAL */
867 StateSaved (snapshot_name); /* EMIT SIGNAL */
874 Session::restore_state (string snapshot_name)
876 if (load_state (snapshot_name) == 0) {
877 set_state (*state_tree->root(), Stateful::loading_state_version);
884 Session::load_state (string snapshot_name)
889 state_was_pending = false;
891 /* check for leftover pending state from a crashed capture attempt */
893 std::string xmlpath(_session_dir->root_path());
894 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
896 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
898 /* there is pending state from a crashed capture attempt */
900 boost::optional<int> r = AskAboutPendingState();
901 if (r.get_value_or (1)) {
902 state_was_pending = true;
906 if (!state_was_pending) {
907 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
910 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
911 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
912 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
913 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
918 state_tree = new XMLTree;
922 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
924 if (!state_tree->read (xmlpath)) {
925 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
931 XMLNode& root (*state_tree->root());
933 if (root.name() != X_("Session")) {
934 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
940 const XMLProperty* prop;
942 if ((prop = root.property ("version")) == 0) {
943 /* no version implies very old version of Ardour */
944 Stateful::loading_state_version = 1000;
946 if (prop->value().find ('.') != string::npos) {
947 /* old school version format */
948 if (prop->value()[0] == '2') {
949 Stateful::loading_state_version = 2000;
951 Stateful::loading_state_version = 3000;
954 Stateful::loading_state_version = atoi (prop->value());
958 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
960 std::string backup_path(_session_dir->root_path());
961 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
962 backup_path = Glib::build_filename (backup_path, backup_filename);
964 // only create a backup for a given statefile version once
966 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
968 VersionMismatch (xmlpath, backup_path);
970 if (!copy_file (xmlpath, backup_path)) {;
980 Session::load_options (const XMLNode& node)
982 LocaleGuard lg (X_("C"));
983 config.set_variables (node);
988 Session::save_default_options ()
990 return config.save_state();
1000 Session::get_template()
1002 /* if we don't disable rec-enable, diskstreams
1003 will believe they need to store their capture
1004 sources in their state node.
1007 disable_record (false);
1009 return state(false);
1013 Session::state (bool full_state)
1015 XMLNode* node = new XMLNode("Session");
1019 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1020 node->add_property("version", buf);
1022 /* store configuration settings */
1026 node->add_property ("name", _name);
1027 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
1028 node->add_property ("sample-rate", buf);
1030 if (session_dirs.size() > 1) {
1034 vector<space_and_path>::iterator i = session_dirs.begin();
1035 vector<space_and_path>::iterator next;
1037 ++i; /* skip the first one */
1041 while (i != session_dirs.end()) {
1045 if (next != session_dirs.end()) {
1046 p += G_SEARCHPATH_SEPARATOR;
1055 child = node->add_child ("Path");
1056 child->add_content (p);
1060 /* save the ID counter */
1062 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1063 node->add_property ("id-counter", buf);
1065 /* save the event ID counter */
1067 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1068 node->add_property ("event-counter", buf);
1070 /* various options */
1072 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1073 if (!midi_port_nodes.empty()) {
1074 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1075 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1076 midi_port_stuff->add_child_nocopy (**n);
1078 node->add_child_nocopy (*midi_port_stuff);
1081 node->add_child_nocopy (config.get_variables ());
1083 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1085 child = node->add_child ("Sources");
1088 Glib::Threads::Mutex::Lock sl (source_lock);
1090 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1092 /* Don't save information about non-file Sources, or
1093 * about non-destructive file sources that are empty
1094 * and unused by any regions.
1097 boost::shared_ptr<FileSource> fs;
1099 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1101 if (!fs->destructive()) {
1102 if (fs->empty() && !fs->used()) {
1107 child->add_child_nocopy (siter->second->get_state());
1112 child = node->add_child ("Regions");
1115 Glib::Threads::Mutex::Lock rl (region_lock);
1116 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1117 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1118 boost::shared_ptr<Region> r = i->second;
1119 /* only store regions not attached to playlists */
1120 if (r->playlist() == 0) {
1121 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1122 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1124 child->add_child_nocopy (r->get_state ());
1129 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1131 if (!cassocs.empty()) {
1132 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1134 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1136 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1137 i->first->id().print (buf, sizeof (buf));
1138 can->add_property (X_("copy"), buf);
1139 i->second->id().print (buf, sizeof (buf));
1140 can->add_property (X_("original"), buf);
1141 ca->add_child_nocopy (*can);
1151 node->add_child_nocopy (_locations->get_state());
1154 Locations loc (*this);
1155 // for a template, just create a new Locations, populate it
1156 // with the default start and end, and get the state for that.
1157 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1158 range->set (max_framepos, 0);
1160 XMLNode& locations_state = loc.get_state();
1162 if (ARDOUR::Profile->get_trx() && _locations) {
1163 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1164 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1165 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1166 locations_state.add_child_nocopy ((*i)->get_state ());
1170 node->add_child_nocopy (locations_state);
1173 child = node->add_child ("Bundles");
1175 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1176 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1177 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1179 child->add_child_nocopy (b->get_state());
1184 child = node->add_child ("Routes");
1186 boost::shared_ptr<RouteList> r = routes.reader ();
1188 RoutePublicOrderSorter cmp;
1189 RouteList public_order (*r);
1190 public_order.sort (cmp);
1192 /* the sort should have put control outs first */
1195 assert (_monitor_out == public_order.front());
1198 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1199 if (!(*i)->is_auditioner()) {
1201 child->add_child_nocopy ((*i)->get_state());
1203 child->add_child_nocopy ((*i)->get_template());
1209 playlists->add_state (node, full_state);
1211 child = node->add_child ("RouteGroups");
1212 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1213 child->add_child_nocopy ((*i)->get_state());
1217 XMLNode* gain_child = node->add_child ("Click");
1218 gain_child->add_child_nocopy (_click_io->state (full_state));
1219 gain_child->add_child_nocopy (_click_gain->state (full_state));
1223 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1224 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1228 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1229 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1232 node->add_child_nocopy (_speakers->get_state());
1233 node->add_child_nocopy (_tempo_map->get_state());
1234 node->add_child_nocopy (get_control_protocol_state());
1237 node->add_child_copy (*_extra_xml);
1244 Session::get_control_protocol_state ()
1246 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1247 return cpm.get_state();
1251 Session::set_state (const XMLNode& node, int version)
1255 const XMLProperty* prop;
1258 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1260 if (node.name() != X_("Session")) {
1261 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1265 if ((prop = node.property ("name")) != 0) {
1266 _name = prop->value ();
1269 if ((prop = node.property (X_("sample-rate"))) != 0) {
1271 _nominal_frame_rate = atoi (prop->value());
1273 if (_nominal_frame_rate != _current_frame_rate) {
1274 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1275 if (r.get_value_or (0)) {
1281 setup_raid_path(_session_dir->root_path());
1283 if ((prop = node.property (X_("id-counter"))) != 0) {
1285 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1286 ID::init_counter (x);
1288 /* old sessions used a timebased counter, so fake
1289 the startup ID counter based on a standard
1294 ID::init_counter (now);
1297 if ((prop = node.property (X_("event-counter"))) != 0) {
1298 Evoral::init_event_id_counter (atoi (prop->value()));
1302 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1303 _midi_ports->set_midi_port_states (child->children());
1306 IO::disable_connecting ();
1308 Stateful::save_extra_xml (node);
1310 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1311 load_options (*child);
1312 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1313 load_options (*child);
1315 error << _("Session: XML state has no options section") << endmsg;
1318 if (version >= 3000) {
1319 if ((child = find_named_node (node, "Metadata")) == 0) {
1320 warning << _("Session: XML state has no metadata section") << endmsg;
1321 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1326 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1327 _speakers->set_state (*child, version);
1330 if ((child = find_named_node (node, "Sources")) == 0) {
1331 error << _("Session: XML state has no sources section") << endmsg;
1333 } else if (load_sources (*child)) {
1337 if ((child = find_named_node (node, "TempoMap")) == 0) {
1338 error << _("Session: XML state has no Tempo Map section") << endmsg;
1340 } else if (_tempo_map->set_state (*child, version)) {
1344 if ((child = find_named_node (node, "Locations")) == 0) {
1345 error << _("Session: XML state has no locations section") << endmsg;
1347 } else if (_locations->set_state (*child, version)) {
1351 locations_changed ();
1353 if (_session_range_location) {
1354 AudioFileSource::set_header_position_offset (_session_range_location->start());
1357 if ((child = find_named_node (node, "Regions")) == 0) {
1358 error << _("Session: XML state has no Regions section") << endmsg;
1360 } else if (load_regions (*child)) {
1364 if ((child = find_named_node (node, "Playlists")) == 0) {
1365 error << _("Session: XML state has no playlists section") << endmsg;
1367 } else if (playlists->load (*this, *child)) {
1371 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1373 } else if (playlists->load_unused (*this, *child)) {
1377 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1378 if (load_compounds (*child)) {
1383 if (version >= 3000) {
1384 if ((child = find_named_node (node, "Bundles")) == 0) {
1385 warning << _("Session: XML state has no bundles section") << endmsg;
1388 /* We can't load Bundles yet as they need to be able
1389 to convert from port names to Port objects, which can't happen until
1391 _bundle_xml_node = new XMLNode (*child);
1395 if (version < 3000) {
1396 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1397 error << _("Session: XML state has no diskstreams section") << endmsg;
1399 } else if (load_diskstreams_2X (*child, version)) {
1404 if ((child = find_named_node (node, "Routes")) == 0) {
1405 error << _("Session: XML state has no routes section") << endmsg;
1407 } else if (load_routes (*child, version)) {
1411 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1412 _diskstreams_2X.clear ();
1414 if (version >= 3000) {
1416 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1417 error << _("Session: XML state has no route groups section") << endmsg;
1419 } else if (load_route_groups (*child, version)) {
1423 } else if (version < 3000) {
1425 if ((child = find_named_node (node, "EditGroups")) == 0) {
1426 error << _("Session: XML state has no edit groups section") << endmsg;
1428 } else if (load_route_groups (*child, version)) {
1432 if ((child = find_named_node (node, "MixGroups")) == 0) {
1433 error << _("Session: XML state has no mix groups section") << endmsg;
1435 } else if (load_route_groups (*child, version)) {
1440 if ((child = find_named_node (node, "Click")) == 0) {
1441 warning << _("Session: XML state has no click section") << endmsg;
1442 } else if (_click_io) {
1443 setup_click_state (&node);
1446 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1447 ControlProtocolManager::instance().set_state (*child, version);
1450 update_route_record_state ();
1452 /* here beginneth the second phase ... */
1454 StateReady (); /* EMIT SIGNAL */
1467 Session::load_routes (const XMLNode& node, int version)
1470 XMLNodeConstIterator niter;
1471 RouteList new_routes;
1473 nlist = node.children();
1477 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1479 boost::shared_ptr<Route> route;
1480 if (version < 3000) {
1481 route = XMLRouteFactory_2X (**niter, version);
1483 route = XMLRouteFactory (**niter, version);
1487 error << _("Session: cannot create Route from XML description.") << endmsg;
1491 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1493 new_routes.push_back (route);
1496 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1498 add_routes (new_routes, false, false, false);
1500 BootMessage (_("Finished adding tracks/busses"));
1505 boost::shared_ptr<Route>
1506 Session::XMLRouteFactory (const XMLNode& node, int version)
1508 boost::shared_ptr<Route> ret;
1510 if (node.name() != "Route") {
1514 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1516 DataType type = DataType::AUDIO;
1517 const XMLProperty* prop = node.property("default-type");
1520 type = DataType (prop->value());
1523 assert (type != DataType::NIL);
1527 boost::shared_ptr<Track> track;
1529 if (type == DataType::AUDIO) {
1530 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1532 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1535 if (track->init()) {
1539 if (track->set_state (node, version)) {
1543 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1544 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1549 enum Route::Flag flags = Route::Flag(0);
1550 const XMLProperty* prop = node.property("flags");
1552 flags = Route::Flag (string_2_enum (prop->value(), flags));
1555 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1557 if (r->init () == 0 && r->set_state (node, version) == 0) {
1558 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1559 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1568 boost::shared_ptr<Route>
1569 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1571 boost::shared_ptr<Route> ret;
1573 if (node.name() != "Route") {
1577 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1579 ds_prop = node.property (X_("diskstream"));
1582 DataType type = DataType::AUDIO;
1583 const XMLProperty* prop = node.property("default-type");
1586 type = DataType (prop->value());
1589 assert (type != DataType::NIL);
1593 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1594 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1598 if (i == _diskstreams_2X.end()) {
1599 error << _("Could not find diskstream for route") << endmsg;
1600 return boost::shared_ptr<Route> ();
1603 boost::shared_ptr<Track> track;
1605 if (type == DataType::AUDIO) {
1606 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1608 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1611 if (track->init()) {
1615 if (track->set_state (node, version)) {
1619 track->set_diskstream (*i);
1621 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1622 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1627 enum Route::Flag flags = Route::Flag(0);
1628 const XMLProperty* prop = node.property("flags");
1630 flags = Route::Flag (string_2_enum (prop->value(), flags));
1633 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1635 if (r->init () == 0 && r->set_state (node, version) == 0) {
1636 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1637 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1647 Session::load_regions (const XMLNode& node)
1650 XMLNodeConstIterator niter;
1651 boost::shared_ptr<Region> region;
1653 nlist = node.children();
1657 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1658 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1659 error << _("Session: cannot create Region from XML description.");
1660 const XMLProperty *name = (**niter).property("name");
1663 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1674 Session::load_compounds (const XMLNode& node)
1676 XMLNodeList calist = node.children();
1677 XMLNodeConstIterator caiter;
1678 XMLProperty *caprop;
1680 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1681 XMLNode* ca = *caiter;
1685 if ((caprop = ca->property (X_("original"))) == 0) {
1688 orig_id = caprop->value();
1690 if ((caprop = ca->property (X_("copy"))) == 0) {
1693 copy_id = caprop->value();
1695 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1696 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1698 if (!orig || !copy) {
1699 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1705 RegionFactory::add_compound_association (orig, copy);
1712 Session::load_nested_sources (const XMLNode& node)
1715 XMLNodeConstIterator niter;
1717 nlist = node.children();
1719 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1720 if ((*niter)->name() == "Source") {
1722 /* it may already exist, so don't recreate it unnecessarily
1725 XMLProperty* prop = (*niter)->property (X_("id"));
1727 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1731 ID source_id (prop->value());
1733 if (!source_by_id (source_id)) {
1736 SourceFactory::create (*this, **niter, true);
1738 catch (failed_constructor& err) {
1739 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1746 boost::shared_ptr<Region>
1747 Session::XMLRegionFactory (const XMLNode& node, bool full)
1749 const XMLProperty* type = node.property("type");
1753 const XMLNodeList& nlist = node.children();
1755 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1756 XMLNode *child = (*niter);
1757 if (child->name() == "NestedSource") {
1758 load_nested_sources (*child);
1762 if (!type || type->value() == "audio") {
1763 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1764 } else if (type->value() == "midi") {
1765 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1768 } catch (failed_constructor& err) {
1769 return boost::shared_ptr<Region> ();
1772 return boost::shared_ptr<Region> ();
1775 boost::shared_ptr<AudioRegion>
1776 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1778 const XMLProperty* prop;
1779 boost::shared_ptr<Source> source;
1780 boost::shared_ptr<AudioSource> as;
1782 SourceList master_sources;
1783 uint32_t nchans = 1;
1786 if (node.name() != X_("Region")) {
1787 return boost::shared_ptr<AudioRegion>();
1790 if ((prop = node.property (X_("channels"))) != 0) {
1791 nchans = atoi (prop->value().c_str());
1794 if ((prop = node.property ("name")) == 0) {
1795 cerr << "no name for this region\n";
1799 if ((prop = node.property (X_("source-0"))) == 0) {
1800 if ((prop = node.property ("source")) == 0) {
1801 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1802 return boost::shared_ptr<AudioRegion>();
1806 PBD::ID s_id (prop->value());
1808 if ((source = source_by_id (s_id)) == 0) {
1809 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1810 return boost::shared_ptr<AudioRegion>();
1813 as = boost::dynamic_pointer_cast<AudioSource>(source);
1815 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1816 return boost::shared_ptr<AudioRegion>();
1819 sources.push_back (as);
1821 /* pickup other channels */
1823 for (uint32_t n=1; n < nchans; ++n) {
1824 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1825 if ((prop = node.property (buf)) != 0) {
1827 PBD::ID id2 (prop->value());
1829 if ((source = source_by_id (id2)) == 0) {
1830 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1831 return boost::shared_ptr<AudioRegion>();
1834 as = boost::dynamic_pointer_cast<AudioSource>(source);
1836 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1837 return boost::shared_ptr<AudioRegion>();
1839 sources.push_back (as);
1843 for (uint32_t n = 0; n < nchans; ++n) {
1844 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1845 if ((prop = node.property (buf)) != 0) {
1847 PBD::ID id2 (prop->value());
1849 if ((source = source_by_id (id2)) == 0) {
1850 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1851 return boost::shared_ptr<AudioRegion>();
1854 as = boost::dynamic_pointer_cast<AudioSource>(source);
1856 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1857 return boost::shared_ptr<AudioRegion>();
1859 master_sources.push_back (as);
1864 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1866 /* a final detail: this is the one and only place that we know how long missing files are */
1868 if (region->whole_file()) {
1869 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1870 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1872 sfp->set_length (region->length());
1877 if (!master_sources.empty()) {
1878 if (master_sources.size() != nchans) {
1879 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1881 region->set_master_sources (master_sources);
1889 catch (failed_constructor& err) {
1890 return boost::shared_ptr<AudioRegion>();
1894 boost::shared_ptr<MidiRegion>
1895 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1897 const XMLProperty* prop;
1898 boost::shared_ptr<Source> source;
1899 boost::shared_ptr<MidiSource> ms;
1902 if (node.name() != X_("Region")) {
1903 return boost::shared_ptr<MidiRegion>();
1906 if ((prop = node.property ("name")) == 0) {
1907 cerr << "no name for this region\n";
1911 if ((prop = node.property (X_("source-0"))) == 0) {
1912 if ((prop = node.property ("source")) == 0) {
1913 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1914 return boost::shared_ptr<MidiRegion>();
1918 PBD::ID s_id (prop->value());
1920 if ((source = source_by_id (s_id)) == 0) {
1921 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1922 return boost::shared_ptr<MidiRegion>();
1925 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1927 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1928 return boost::shared_ptr<MidiRegion>();
1931 sources.push_back (ms);
1934 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1935 /* a final detail: this is the one and only place that we know how long missing files are */
1937 if (region->whole_file()) {
1938 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1939 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1941 sfp->set_length (region->length());
1949 catch (failed_constructor& err) {
1950 return boost::shared_ptr<MidiRegion>();
1955 Session::get_sources_as_xml ()
1958 XMLNode* node = new XMLNode (X_("Sources"));
1959 Glib::Threads::Mutex::Lock lm (source_lock);
1961 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1962 node->add_child_nocopy (i->second->get_state());
1969 Session::reset_write_sources (bool mark_write_complete, bool force)
1971 boost::shared_ptr<RouteList> rl = routes.reader();
1972 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1973 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1975 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1976 tr->reset_write_sources(mark_write_complete, force);
1977 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1983 Session::load_sources (const XMLNode& node)
1986 XMLNodeConstIterator niter;
1987 boost::shared_ptr<Source> source; /* don't need this but it stops some
1988 * versions of gcc complaining about
1989 * discarded return values.
1992 nlist = node.children();
1996 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1999 if ((source = XMLSourceFactory (**niter)) == 0) {
2000 error << _("Session: cannot create Source from XML description.") << endmsg;
2003 } catch (MissingSource& err) {
2007 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2008 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2009 PROGRAM_NAME) << endmsg;
2013 if (!no_questions_about_missing_files) {
2014 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2019 switch (user_choice) {
2021 /* user added a new search location, so try again */
2026 /* user asked to quit the entire session load
2031 no_questions_about_missing_files = true;
2035 no_questions_about_missing_files = true;
2042 case DataType::AUDIO:
2043 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2046 case DataType::MIDI:
2047 /* The MIDI file is actually missing so
2048 * just create a new one in the same
2049 * location. Do not announce its
2053 if (!Glib::path_is_absolute (err.path)) {
2054 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2056 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2061 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2062 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2063 /* reset ID to match the missing one */
2064 source->set_id (**niter);
2065 /* Now we can announce it */
2066 SourceFactory::SourceCreated (source);
2077 boost::shared_ptr<Source>
2078 Session::XMLSourceFactory (const XMLNode& node)
2080 if (node.name() != "Source") {
2081 return boost::shared_ptr<Source>();
2085 /* note: do peak building in another thread when loading session state */
2086 return SourceFactory::create (*this, node, true);
2089 catch (failed_constructor& err) {
2090 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2091 return boost::shared_ptr<Source>();
2096 Session::save_template (string template_name)
2098 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2102 bool absolute_path = Glib::path_is_absolute (template_name);
2104 /* directory to put the template in */
2105 std::string template_dir_path;
2107 if (!absolute_path) {
2108 std::string user_template_dir(user_template_directory());
2110 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2111 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2112 user_template_dir, g_strerror (errno)) << endmsg;
2116 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2118 template_dir_path = template_name;
2121 if (!ARDOUR::Profile->get_trx()) {
2122 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2123 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2124 template_dir_path) << endmsg;
2128 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2129 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2130 template_dir_path, g_strerror (errno)) << endmsg;
2136 std::string template_file_path;
2138 if (ARDOUR::Profile->get_trx()) {
2139 template_file_path = template_name;
2141 if (absolute_path) {
2142 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2144 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2148 SessionSaveUnderway (); /* EMIT SIGNAL */
2152 tree.set_root (&get_template());
2153 if (!tree.write (template_file_path)) {
2154 error << _("template not saved") << endmsg;
2158 if (!ARDOUR::Profile->get_trx()) {
2159 /* copy plugin state directory */
2161 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2163 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2164 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2165 template_plugin_state_path, g_strerror (errno)) << endmsg;
2168 copy_files (plugins_dir(), template_plugin_state_path);
2171 store_recent_templates (template_file_path);
2177 Session::refresh_disk_space ()
2179 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2181 Glib::Threads::Mutex::Lock lm (space_lock);
2183 /* get freespace on every FS that is part of the session path */
2185 _total_free_4k_blocks = 0;
2186 _total_free_4k_blocks_uncertain = false;
2188 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2190 struct statfs statfsbuf;
2191 statfs (i->path.c_str(), &statfsbuf);
2193 double const scale = statfsbuf.f_bsize / 4096.0;
2195 /* See if this filesystem is read-only */
2196 struct statvfs statvfsbuf;
2197 statvfs (i->path.c_str(), &statvfsbuf);
2199 /* f_bavail can be 0 if it is undefined for whatever
2200 filesystem we are looking at; Samba shares mounted
2201 via GVFS are an example of this.
2203 if (statfsbuf.f_bavail == 0) {
2204 /* block count unknown */
2206 i->blocks_unknown = true;
2207 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2208 /* read-only filesystem */
2210 i->blocks_unknown = false;
2212 /* read/write filesystem with known space */
2213 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2214 i->blocks_unknown = false;
2217 _total_free_4k_blocks += i->blocks;
2218 if (i->blocks_unknown) {
2219 _total_free_4k_blocks_uncertain = true;
2222 #elif defined PLATFORM_WINDOWS
2223 vector<string> scanned_volumes;
2224 vector<string>::iterator j;
2225 vector<space_and_path>::iterator i;
2226 DWORD nSectorsPerCluster, nBytesPerSector,
2227 nFreeClusters, nTotalClusters;
2231 _total_free_4k_blocks = 0;
2233 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2234 strncpy (disk_drive, (*i).path.c_str(), 3);
2238 volume_found = false;
2239 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2241 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2242 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2243 i->blocks = (uint32_t)(nFreeBytes / 4096);
2245 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2246 if (0 == j->compare(disk_drive)) {
2247 volume_found = true;
2252 if (!volume_found) {
2253 scanned_volumes.push_back(disk_drive);
2254 _total_free_4k_blocks += i->blocks;
2259 if (0 == _total_free_4k_blocks) {
2260 strncpy (disk_drive, path().c_str(), 3);
2263 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2265 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2266 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2267 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2274 Session::get_best_session_directory_for_new_audio ()
2276 vector<space_and_path>::iterator i;
2277 string result = _session_dir->root_path();
2279 /* handle common case without system calls */
2281 if (session_dirs.size() == 1) {
2285 /* OK, here's the algorithm we're following here:
2287 We want to select which directory to use for
2288 the next file source to be created. Ideally,
2289 we'd like to use a round-robin process so as to
2290 get maximum performance benefits from splitting
2291 the files across multiple disks.
2293 However, in situations without much diskspace, an
2294 RR approach may end up filling up a filesystem
2295 with new files while others still have space.
2296 Its therefore important to pay some attention to
2297 the freespace in the filesystem holding each
2298 directory as well. However, if we did that by
2299 itself, we'd keep creating new files in the file
2300 system with the most space until it was as full
2301 as all others, thus negating any performance
2302 benefits of this RAID-1 like approach.
2304 So, we use a user-configurable space threshold. If
2305 there are at least 2 filesystems with more than this
2306 much space available, we use RR selection between them.
2307 If not, then we pick the filesystem with the most space.
2309 This gets a good balance between the two
2313 refresh_disk_space ();
2315 int free_enough = 0;
2317 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2318 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2323 if (free_enough >= 2) {
2324 /* use RR selection process, ensuring that the one
2328 i = last_rr_session_dir;
2331 if (++i == session_dirs.end()) {
2332 i = session_dirs.begin();
2335 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2336 SessionDirectory sdir(i->path);
2337 if (sdir.create ()) {
2339 last_rr_session_dir = i;
2344 } while (i != last_rr_session_dir);
2348 /* pick FS with the most freespace (and that
2349 seems to actually work ...)
2352 vector<space_and_path> sorted;
2353 space_and_path_ascending_cmp cmp;
2355 sorted = session_dirs;
2356 sort (sorted.begin(), sorted.end(), cmp);
2358 for (i = sorted.begin(); i != sorted.end(); ++i) {
2359 SessionDirectory sdir(i->path);
2360 if (sdir.create ()) {
2362 last_rr_session_dir = i;
2372 Session::automation_dir () const
2374 return Glib::build_filename (_path, automation_dir_name);
2378 Session::analysis_dir () const
2380 return Glib::build_filename (_path, analysis_dir_name);
2384 Session::plugins_dir () const
2386 return Glib::build_filename (_path, plugins_dir_name);
2390 Session::externals_dir () const
2392 return Glib::build_filename (_path, externals_dir_name);
2396 Session::load_bundles (XMLNode const & node)
2398 XMLNodeList nlist = node.children();
2399 XMLNodeConstIterator niter;
2403 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2404 if ((*niter)->name() == "InputBundle") {
2405 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2406 } else if ((*niter)->name() == "OutputBundle") {
2407 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2409 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2418 Session::load_route_groups (const XMLNode& node, int version)
2420 XMLNodeList nlist = node.children();
2421 XMLNodeConstIterator niter;
2425 if (version >= 3000) {
2427 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2428 if ((*niter)->name() == "RouteGroup") {
2429 RouteGroup* rg = new RouteGroup (*this, "");
2430 add_route_group (rg);
2431 rg->set_state (**niter, version);
2435 } else if (version < 3000) {
2437 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2438 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2439 RouteGroup* rg = new RouteGroup (*this, "");
2440 add_route_group (rg);
2441 rg->set_state (**niter, version);
2450 state_file_filter (const string &str, void* /*arg*/)
2452 return (str.length() > strlen(statefile_suffix) &&
2453 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2457 remove_end(string state)
2459 string statename(state);
2461 string::size_type start,end;
2462 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2463 statename = statename.substr (start+1);
2466 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2467 end = statename.length();
2470 return string(statename.substr (0, end));
2474 Session::possible_states (string path)
2476 vector<string> states;
2477 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2479 transform(states.begin(), states.end(), states.begin(), remove_end);
2481 sort (states.begin(), states.end());
2487 Session::possible_states () const
2489 return possible_states(_path);
2493 Session::add_route_group (RouteGroup* g)
2495 _route_groups.push_back (g);
2496 route_group_added (g); /* EMIT SIGNAL */
2498 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2499 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2500 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2506 Session::remove_route_group (RouteGroup& rg)
2508 list<RouteGroup*>::iterator i;
2510 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2511 _route_groups.erase (i);
2514 route_group_removed (); /* EMIT SIGNAL */
2518 /** Set a new order for our route groups, without adding or removing any.
2519 * @param groups Route group list in the new order.
2522 Session::reorder_route_groups (list<RouteGroup*> groups)
2524 _route_groups = groups;
2526 route_groups_reordered (); /* EMIT SIGNAL */
2532 Session::route_group_by_name (string name)
2534 list<RouteGroup *>::iterator i;
2536 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2537 if ((*i)->name() == name) {
2545 Session::all_route_group() const
2547 return *_all_route_group;
2551 Session::add_commands (vector<Command*> const & cmds)
2553 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2559 Session::add_command (Command* const cmd)
2561 assert (_current_trans);
2562 DEBUG_UNDO_HISTORY (
2563 string_compose ("Current Undo Transaction %1, adding command: %2",
2564 _current_trans->name (),
2566 _current_trans->add_command (cmd);
2569 Session::begin_reversible_command (const string& name)
2571 begin_reversible_command (g_quark_from_string (name.c_str ()));
2574 /** Begin a reversible command using a GQuark to identify it.
2575 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2576 * but there must be as many begin...()s as there are commit...()s.
2579 Session::begin_reversible_command (GQuark q)
2581 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2582 to hold all the commands that are committed. This keeps the order of
2583 commands correct in the history.
2586 if (_current_trans == 0) {
2587 DEBUG_UNDO_HISTORY (string_compose (
2588 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2590 /* start a new transaction */
2591 assert (_current_trans_quarks.empty ());
2592 _current_trans = new UndoTransaction();
2593 _current_trans->set_name (g_quark_to_string (q));
2595 DEBUG_UNDO_HISTORY (
2596 string_compose ("Begin Reversible Command, current transaction: %1",
2597 _current_trans->name ()));
2600 _current_trans_quarks.push_front (q);
2604 Session::abort_reversible_command ()
2606 if (_current_trans != 0) {
2607 DEBUG_UNDO_HISTORY (
2608 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2609 _current_trans->clear();
2610 delete _current_trans;
2612 _current_trans_quarks.clear();
2617 Session::commit_reversible_command (Command *cmd)
2619 assert (_current_trans);
2620 assert (!_current_trans_quarks.empty ());
2625 DEBUG_UNDO_HISTORY (
2626 string_compose ("Current Undo Transaction %1, adding command: %2",
2627 _current_trans->name (),
2629 _current_trans->add_command (cmd);
2632 DEBUG_UNDO_HISTORY (
2633 string_compose ("Commit Reversible Command, current transaction: %1",
2634 _current_trans->name ()));
2636 _current_trans_quarks.pop_front ();
2638 if (!_current_trans_quarks.empty ()) {
2639 DEBUG_UNDO_HISTORY (
2640 string_compose ("Commit Reversible Command, transaction is not "
2641 "top-level, current transaction: %1",
2642 _current_trans->name ()));
2643 /* the transaction we're committing is not the top-level one */
2647 if (_current_trans->empty()) {
2648 /* no commands were added to the transaction, so just get rid of it */
2649 DEBUG_UNDO_HISTORY (
2650 string_compose ("Commit Reversible Command, No commands were "
2651 "added to current transaction: %1",
2652 _current_trans->name ()));
2653 delete _current_trans;
2658 gettimeofday (&now, 0);
2659 _current_trans->set_timestamp (now);
2661 _history.add (_current_trans);
2666 accept_all_audio_files (const string& path, void* /*arg*/)
2668 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2672 if (!AudioFileSource::safe_audio_file_extension (path)) {
2680 accept_all_midi_files (const string& path, void* /*arg*/)
2682 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2686 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2687 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2688 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2692 accept_all_state_files (const string& path, void* /*arg*/)
2694 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2698 std::string const statefile_ext (statefile_suffix);
2699 if (path.length() >= statefile_ext.length()) {
2700 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2707 Session::find_all_sources (string path, set<string>& result)
2712 if (!tree.read (path)) {
2716 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2721 XMLNodeConstIterator niter;
2723 nlist = node->children();
2727 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2731 if ((prop = (*niter)->property (X_("type"))) == 0) {
2735 DataType type (prop->value());
2737 if ((prop = (*niter)->property (X_("name"))) == 0) {
2741 if (Glib::path_is_absolute (prop->value())) {
2742 /* external file, ignore */
2750 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2751 result.insert (found_path);
2759 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2761 vector<string> state_files;
2763 string this_snapshot_path;
2769 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2770 ripped = ripped.substr (0, ripped.length() - 1);
2773 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2775 if (state_files.empty()) {
2780 this_snapshot_path = _path;
2781 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2782 this_snapshot_path += statefile_suffix;
2784 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2786 if (exclude_this_snapshot && *i == this_snapshot_path) {
2790 if (find_all_sources (*i, result) < 0) {
2798 struct RegionCounter {
2799 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2800 AudioSourceList::iterator iter;
2801 boost::shared_ptr<Region> region;
2804 RegionCounter() : count (0) {}
2808 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2810 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2811 return r.get_value_or (1);
2815 Session::cleanup_regions ()
2817 bool removed = false;
2818 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2820 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2822 uint32_t used = playlists->region_use_count (i->second);
2824 if (used == 0 && !i->second->automatic ()) {
2826 RegionFactory::map_remove (i->second);
2831 // re-check to remove parent references of compound regions
2832 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2833 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2836 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2837 if (0 == playlists->region_use_count (i->second)) {
2838 RegionFactory::map_remove (i->second);
2843 /* dump the history list */
2850 Session::can_cleanup_peakfiles () const
2852 if (deletion_in_progress()) {
2855 if (!_writable || (_state_of_the_state & CannotSave)) {
2856 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2859 if (record_status() == Recording) {
2860 error << _("Cannot cleanup peak-files while recording") << endmsg;
2867 Session::cleanup_peakfiles ()
2869 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2874 assert (can_cleanup_peakfiles ());
2875 assert (!peaks_cleanup_in_progres());
2877 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2879 int timeout = 5000; // 5 seconds
2880 while (!SourceFactory::files_with_peaks.empty()) {
2881 Glib::usleep (1000);
2882 if (--timeout < 0) {
2883 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2884 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2889 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2890 boost::shared_ptr<AudioSource> as;
2891 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2892 as->close_peakfile();
2896 PBD::clear_directory (session_directory().peak_path());
2898 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2900 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2901 boost::shared_ptr<AudioSource> as;
2902 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2903 SourceFactory::setup_peakfile(as, true);
2910 Session::cleanup_sources (CleanupReport& rep)
2912 // FIXME: needs adaptation to midi
2914 vector<boost::shared_ptr<Source> > dead_sources;
2917 vector<string> candidates;
2918 vector<string> unused;
2919 set<string> all_sources;
2928 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2930 /* consider deleting all unused playlists */
2932 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2937 /* sync the "all regions" property of each playlist with its current state
2940 playlists->sync_all_regions_with_regions ();
2942 /* find all un-used sources */
2947 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2949 SourceMap::iterator tmp;
2954 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2958 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2959 dead_sources.push_back (i->second);
2960 i->second->drop_references ();
2966 /* build a list of all the possible audio directories for the session */
2968 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2969 SessionDirectory sdir ((*i).path);
2970 asp += sdir.sound_path();
2972 audio_path += asp.to_string();
2975 /* build a list of all the possible midi directories for the session */
2977 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2978 SessionDirectory sdir ((*i).path);
2979 msp += sdir.midi_path();
2981 midi_path += msp.to_string();
2983 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2984 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2986 /* find all sources, but don't use this snapshot because the
2987 state file on disk still references sources we may have already
2991 find_all_sources_across_snapshots (all_sources, true);
2993 /* add our current source list
2996 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2997 boost::shared_ptr<FileSource> fs;
2998 SourceMap::iterator tmp = i;
3001 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3003 if (!fs->is_stub()) {
3005 if (playlists->source_use_count (fs) != 0) {
3006 all_sources.insert (fs->path());
3009 /* we might not remove this source from disk, because it may be used
3010 by other snapshots, but its not being used in this version
3011 so lets get rid of it now, along with any representative regions
3015 RegionFactory::remove_regions_using_source (i->second);
3017 // also remove source from all_sources
3019 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3020 spath = Glib::path_get_basename (*j);
3021 if (spath == i->second->name()) {
3022 all_sources.erase (j);
3035 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3040 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3042 tmppath1 = canonical_path (spath);
3043 tmppath2 = canonical_path ((*i));
3045 if (tmppath1 == tmppath2) {
3052 unused.push_back (spath);
3056 /* now try to move all unused files into the "dead" directory(ies) */
3058 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3059 struct stat statbuf;
3063 /* don't move the file across filesystems, just
3064 stick it in the `dead_dir_name' directory
3065 on whichever filesystem it was already on.
3068 if ((*x).find ("/sounds/") != string::npos) {
3070 /* old school, go up 1 level */
3072 newpath = Glib::path_get_dirname (*x); // "sounds"
3073 newpath = Glib::path_get_dirname (newpath); // "session-name"
3077 /* new school, go up 4 levels */
3079 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3080 newpath = Glib::path_get_dirname (newpath); // "session-name"
3081 newpath = Glib::path_get_dirname (newpath); // "interchange"
3082 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3085 newpath = Glib::build_filename (newpath, dead_dir_name);
3087 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3088 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3092 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3094 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3096 /* the new path already exists, try versioning */
3098 char buf[PATH_MAX+1];
3102 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3105 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3106 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3110 if (version == 999) {
3111 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3115 newpath = newpath_v;
3120 /* it doesn't exist, or we can't read it or something */
3124 stat ((*x).c_str(), &statbuf);
3126 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3127 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3128 (*x), newpath, strerror (errno))
3133 /* see if there an easy to find peakfile for this file, and remove it.
3136 string base = Glib::path_get_basename (*x);
3137 base += "%A"; /* this is what we add for the channel suffix of all native files,
3138 or for the first channel of embedded files. it will miss
3139 some peakfiles for other channels
3141 string peakpath = construct_peak_filepath (base);
3143 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3144 if (::g_unlink (peakpath.c_str()) != 0) {
3145 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3146 peakpath, _path, strerror (errno))
3148 /* try to back out */
3149 ::rename (newpath.c_str(), _path.c_str());
3154 rep.paths.push_back (*x);
3155 rep.space += statbuf.st_size;
3158 /* dump the history list */
3162 /* save state so we don't end up a session file
3163 referring to non-existent sources.
3170 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3176 Session::cleanup_trash_sources (CleanupReport& rep)
3178 // FIXME: needs adaptation for MIDI
3180 vector<space_and_path>::iterator i;
3186 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3188 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3190 clear_directory (dead_dir, &rep.space, &rep.paths);
3197 Session::set_dirty ()
3199 /* never mark session dirty during loading */
3201 if (_state_of_the_state & Loading) {
3205 bool was_dirty = dirty();
3207 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3211 DirtyChanged(); /* EMIT SIGNAL */
3217 Session::set_clean ()
3219 bool was_dirty = dirty();
3221 _state_of_the_state = Clean;
3225 DirtyChanged(); /* EMIT SIGNAL */
3230 Session::set_deletion_in_progress ()
3232 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3236 Session::clear_deletion_in_progress ()
3238 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3242 Session::add_controllable (boost::shared_ptr<Controllable> c)
3244 /* this adds a controllable to the list managed by the Session.
3245 this is a subset of those managed by the Controllable class
3246 itself, and represents the only ones whose state will be saved
3247 as part of the session.
3250 Glib::Threads::Mutex::Lock lm (controllables_lock);
3251 controllables.insert (c);
3254 struct null_deleter { void operator()(void const *) const {} };
3257 Session::remove_controllable (Controllable* c)
3259 if (_state_of_the_state & Deletion) {
3263 Glib::Threads::Mutex::Lock lm (controllables_lock);
3265 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3267 if (x != controllables.end()) {
3268 controllables.erase (x);
3272 boost::shared_ptr<Controllable>
3273 Session::controllable_by_id (const PBD::ID& id)
3275 Glib::Threads::Mutex::Lock lm (controllables_lock);
3277 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3278 if ((*i)->id() == id) {
3283 return boost::shared_ptr<Controllable>();
3286 boost::shared_ptr<Controllable>
3287 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3289 boost::shared_ptr<Controllable> c;
3290 boost::shared_ptr<Route> r;
3292 switch (desc.top_level_type()) {
3293 case ControllableDescriptor::NamedRoute:
3295 std::string str = desc.top_level_name();
3296 if (str == "Master" || str == "master") {
3298 } else if (str == "control" || str == "listen") {
3301 r = route_by_name (desc.top_level_name());
3306 case ControllableDescriptor::RemoteControlID:
3307 r = route_by_remote_id (desc.rid());
3315 switch (desc.subtype()) {
3316 case ControllableDescriptor::Gain:
3317 c = r->gain_control ();
3320 case ControllableDescriptor::Trim:
3321 c = r->trim()->gain_control ();
3324 case ControllableDescriptor::Solo:
3325 c = r->solo_control();
3328 case ControllableDescriptor::Mute:
3329 c = r->mute_control();
3332 case ControllableDescriptor::Recenable:
3334 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3337 c = t->rec_enable_control ();
3342 case ControllableDescriptor::PanDirection:
3344 c = r->pannable()->pan_azimuth_control;
3348 case ControllableDescriptor::PanWidth:
3350 c = r->pannable()->pan_width_control;
3354 case ControllableDescriptor::PanElevation:
3356 c = r->pannable()->pan_elevation_control;
3360 case ControllableDescriptor::Balance:
3361 /* XXX simple pan control */
3364 case ControllableDescriptor::PluginParameter:
3366 uint32_t plugin = desc.target (0);
3367 uint32_t parameter_index = desc.target (1);
3369 /* revert to zero based counting */
3375 if (parameter_index > 0) {
3379 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3382 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3383 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3388 case ControllableDescriptor::SendGain:
3390 uint32_t send = desc.target (0);
3392 /* revert to zero-based counting */
3398 boost::shared_ptr<Processor> p = r->nth_send (send);
3401 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3402 boost::shared_ptr<Amp> a = s->amp();
3405 c = s->amp()->gain_control();
3412 /* relax and return a null pointer */
3420 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3423 Stateful::add_instant_xml (node, _path);
3426 if (write_to_config) {
3427 Config->add_instant_xml (node);
3432 Session::instant_xml (const string& node_name)
3434 return Stateful::instant_xml (node_name, _path);
3438 Session::save_history (string snapshot_name)
3446 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3447 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3451 if (snapshot_name.empty()) {
3452 snapshot_name = _current_snapshot_name;
3455 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3456 const string backup_filename = history_filename + backup_suffix;
3457 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3458 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3460 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3461 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3462 error << _("could not backup old history file, current history not saved") << endmsg;
3467 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3469 if (!tree.write (xml_path))
3471 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3473 if (g_remove (xml_path.c_str()) != 0) {
3474 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3475 xml_path, g_strerror (errno)) << endmsg;
3477 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3478 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3479 backup_path, g_strerror (errno)) << endmsg;
3489 Session::restore_history (string snapshot_name)
3493 if (snapshot_name.empty()) {
3494 snapshot_name = _current_snapshot_name;
3497 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3498 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3500 info << "Loading history from " << xml_path << endmsg;
3502 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3503 info << string_compose (_("%1: no history file \"%2\" for this session."),
3504 _name, xml_path) << endmsg;
3508 if (!tree.read (xml_path)) {
3509 error << string_compose (_("Could not understand session history file \"%1\""),
3510 xml_path) << endmsg;
3517 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3520 UndoTransaction* ut = new UndoTransaction ();
3523 ut->set_name(t->property("name")->value());
3524 stringstream ss(t->property("tv-sec")->value());
3526 ss.str(t->property("tv-usec")->value());
3528 ut->set_timestamp(tv);
3530 for (XMLNodeConstIterator child_it = t->children().begin();
3531 child_it != t->children().end(); child_it++)
3533 XMLNode *n = *child_it;
3536 if (n->name() == "MementoCommand" ||
3537 n->name() == "MementoUndoCommand" ||
3538 n->name() == "MementoRedoCommand") {
3540 if ((c = memento_command_factory(n))) {
3544 } else if (n->name() == "NoteDiffCommand") {
3545 PBD::ID id (n->property("midi-source")->value());
3546 boost::shared_ptr<MidiSource> midi_source =
3547 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3549 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3551 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3554 } else if (n->name() == "SysExDiffCommand") {
3556 PBD::ID id (n->property("midi-source")->value());
3557 boost::shared_ptr<MidiSource> midi_source =
3558 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3560 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3562 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3565 } else if (n->name() == "PatchChangeDiffCommand") {
3567 PBD::ID id (n->property("midi-source")->value());
3568 boost::shared_ptr<MidiSource> midi_source =
3569 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3571 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3573 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3576 } else if (n->name() == "StatefulDiffCommand") {
3577 if ((c = stateful_diff_command_factory (n))) {
3578 ut->add_command (c);
3581 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3592 Session::config_changed (std::string p, bool ours)
3598 if (p == "seamless-loop") {
3600 } else if (p == "rf-speed") {
3602 } else if (p == "auto-loop") {
3604 } else if (p == "auto-input") {
3606 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3607 /* auto-input only makes a difference if we're rolling */
3608 set_track_monitor_input_status (!config.get_auto_input());
3611 } else if (p == "punch-in") {
3615 if ((location = _locations->auto_punch_location()) != 0) {
3617 if (config.get_punch_in ()) {
3618 replace_event (SessionEvent::PunchIn, location->start());
3620 remove_event (location->start(), SessionEvent::PunchIn);
3624 } else if (p == "punch-out") {
3628 if ((location = _locations->auto_punch_location()) != 0) {
3630 if (config.get_punch_out()) {
3631 replace_event (SessionEvent::PunchOut, location->end());
3633 clear_events (SessionEvent::PunchOut);
3637 } else if (p == "edit-mode") {
3639 Glib::Threads::Mutex::Lock lm (playlists->lock);
3641 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3642 (*i)->set_edit_mode (Config->get_edit_mode ());
3645 } else if (p == "use-video-sync") {
3647 waiting_for_sync_offset = config.get_use_video_sync();
3649 } else if (p == "mmc-control") {
3651 //poke_midi_thread ();
3653 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3655 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3657 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3659 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3661 } else if (p == "midi-control") {
3663 //poke_midi_thread ();
3665 } else if (p == "raid-path") {
3667 setup_raid_path (config.get_raid_path());
3669 } else if (p == "timecode-format") {
3673 } else if (p == "video-pullup") {
3677 } else if (p == "seamless-loop") {
3679 if (play_loop && transport_rolling()) {
3680 // to reset diskstreams etc
3681 request_play_loop (true);
3684 } else if (p == "rf-speed") {
3686 cumulative_rf_motion = 0;
3689 } else if (p == "click-sound") {
3691 setup_click_sounds (1);
3693 } else if (p == "click-emphasis-sound") {
3695 setup_click_sounds (-1);
3697 } else if (p == "clicking") {
3699 if (Config->get_clicking()) {
3700 if (_click_io && click_data) { // don't require emphasis data
3707 } else if (p == "click-gain") {
3710 _click_gain->set_gain (Config->get_click_gain(), this);
3713 } else if (p == "send-mtc") {
3715 if (Config->get_send_mtc ()) {
3716 /* mark us ready to send */
3717 next_quarter_frame_to_send = 0;
3720 } else if (p == "send-mmc") {
3722 _mmc->enable_send (Config->get_send_mmc ());
3724 } else if (p == "midi-feedback") {
3726 session_midi_feedback = Config->get_midi_feedback();
3728 } else if (p == "jack-time-master") {
3730 engine().reset_timebase ();
3732 } else if (p == "native-file-header-format") {
3734 if (!first_file_header_format_reset) {
3735 reset_native_file_format ();
3738 first_file_header_format_reset = false;
3740 } else if (p == "native-file-data-format") {
3742 if (!first_file_data_format_reset) {
3743 reset_native_file_format ();
3746 first_file_data_format_reset = false;
3748 } else if (p == "external-sync") {
3749 if (!config.get_external_sync()) {
3750 drop_sync_source ();
3752 switch_to_sync_source (Config->get_sync_source());
3754 } else if (p == "denormal-model") {
3756 } else if (p == "history-depth") {
3757 set_history_depth (Config->get_history_depth());
3758 } else if (p == "remote-model") {
3759 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3762 } else if (p == "initial-program-change") {
3764 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3767 buf[0] = MIDI::program; // channel zero by default
3768 buf[1] = (Config->get_initial_program_change() & 0x7f);
3770 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3772 } else if (p == "solo-mute-override") {
3773 // catch_up_on_solo_mute_override ();
3774 } else if (p == "listen-position" || p == "pfl-position") {
3775 listen_position_changed ();
3776 } else if (p == "solo-control-is-listen-control") {
3777 solo_control_mode_changed ();
3778 } else if (p == "solo-mute-gain") {
3779 _solo_cut_control->Changed();
3780 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3781 last_timecode_valid = false;
3782 } else if (p == "playback-buffer-seconds") {
3783 AudioSource::allocate_working_buffers (frame_rate());
3784 } else if (p == "ltc-source-port") {
3785 reconnect_ltc_input ();
3786 } else if (p == "ltc-sink-port") {
3787 reconnect_ltc_output ();
3788 } else if (p == "timecode-generator-offset") {
3789 ltc_tx_parse_offset();
3790 } else if (p == "auto-return-target-list") {
3791 follow_playhead_priority ();
3798 Session::set_history_depth (uint32_t d)
3800 _history.set_depth (d);
3804 Session::load_diskstreams_2X (XMLNode const & node, int)
3807 XMLNodeConstIterator citer;
3809 clist = node.children();
3811 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3814 /* diskstreams added automatically by DiskstreamCreated handler */
3815 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3816 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3817 _diskstreams_2X.push_back (dsp);
3819 error << _("Session: unknown diskstream type in XML") << endmsg;
3823 catch (failed_constructor& err) {
3824 error << _("Session: could not load diskstream via XML state") << endmsg;
3832 /** Connect things to the MMC object */
3834 Session::setup_midi_machine_control ()
3836 _mmc = new MIDI::MachineControl;
3837 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3839 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3840 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3841 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3842 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3843 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3844 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3845 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3846 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3847 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3848 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3849 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3850 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3851 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3853 /* also handle MIDI SPP because its so common */
3855 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3856 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3857 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3860 boost::shared_ptr<Controllable>
3861 Session::solo_cut_control() const
3863 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3864 controls in Ardour that currently get presented to the user in the GUI that require
3865 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3867 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3868 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3872 return _solo_cut_control;
3876 Session::rename (const std::string& new_name)
3878 string legal_name = legalize_for_path (new_name);
3884 string const old_sources_root = _session_dir->sources_root();
3886 if (!_writable || (_state_of_the_state & CannotSave)) {
3887 error << _("Cannot rename read-only session.") << endmsg;
3888 return 0; // don't show "messed up" warning
3890 if (record_status() == Recording) {
3891 error << _("Cannot rename session while recording") << endmsg;
3892 return 0; // don't show "messed up" warning
3895 StateProtector stp (this);
3900 * interchange subdirectory
3904 * Backup files are left unchanged and not renamed.
3907 /* Windows requires that we close all files before attempting the
3908 * rename. This works on other platforms, but isn't necessary there.
3909 * Leave it in place for all platforms though, since it may help
3910 * catch issues that could arise if the way Source files work ever
3911 * change (since most developers are not using Windows).
3914 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3915 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3921 /* pass one: not 100% safe check that the new directory names don't
3925 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3929 /* this is a stupid hack because Glib::path_get_dirname() is
3930 * lexical-only, and so passing it /a/b/c/ gives a different
3931 * result than passing it /a/b/c ...
3934 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3935 oldstr = oldstr.substr (0, oldstr.length() - 1);
3938 string base = Glib::path_get_dirname (oldstr);
3940 newstr = Glib::build_filename (base, legal_name);
3942 cerr << "Looking for " << newstr << endl;
3944 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3945 cerr << " exists\n";
3954 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3960 /* this is a stupid hack because Glib::path_get_dirname() is
3961 * lexical-only, and so passing it /a/b/c/ gives a different
3962 * result than passing it /a/b/c ...
3965 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3966 oldstr = oldstr.substr (0, oldstr.length() - 1);
3969 string base = Glib::path_get_dirname (oldstr);
3970 newstr = Glib::build_filename (base, legal_name);
3972 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3974 cerr << "Rename " << oldstr << " => " << newstr << endl;
3975 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3976 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3977 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3981 /* Reset path in "session dirs" */
3986 /* reset primary SessionDirectory object */
3989 (*_session_dir) = newstr;
3994 /* now rename directory below session_dir/interchange */
3996 string old_interchange_dir;
3997 string new_interchange_dir;
3999 /* use newstr here because we renamed the path
4000 * (folder/directory) that used to be oldstr to newstr above
4003 v.push_back (newstr);
4004 v.push_back (interchange_dir_name);
4005 v.push_back (Glib::path_get_basename (oldstr));
4007 old_interchange_dir = Glib::build_filename (v);
4010 v.push_back (newstr);
4011 v.push_back (interchange_dir_name);
4012 v.push_back (legal_name);
4014 new_interchange_dir = Glib::build_filename (v);
4016 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4018 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4019 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4020 old_interchange_dir, new_interchange_dir,
4023 error << string_compose (_("renaming %s as %2 failed (%3)"),
4024 old_interchange_dir, new_interchange_dir,
4033 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4034 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4036 cerr << "Rename " << oldstr << " => " << newstr << endl;
4038 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4039 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4040 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4046 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4048 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4049 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4051 cerr << "Rename " << oldstr << " => " << newstr << endl;
4053 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4054 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4055 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4060 /* remove old name from recent sessions */
4061 remove_recent_sessions (_path);
4064 /* update file source paths */
4066 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4067 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4069 string p = fs->path ();
4070 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4072 SourceFactory::setup_peakfile(i->second, true);
4076 _current_snapshot_name = new_name;
4081 /* save state again to get everything just right */
4083 save_state (_current_snapshot_name);
4085 /* add to recent sessions */
4087 store_recent_sessions (new_name, _path);
4093 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4095 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4099 if (!tree.read (xmlpath)) {
4107 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4110 bool found_sr = false;
4111 bool found_data_format = false;
4113 if (get_session_info_from_path (tree, xmlpath)) {
4119 const XMLProperty* prop;
4120 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
4121 sample_rate = atoi (prop->value());
4125 const XMLNodeList& children (tree.root()->children());
4126 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4127 const XMLNode* child = *c;
4128 if (child->name() == "Config") {
4129 const XMLNodeList& options (child->children());
4130 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4131 const XMLNode* option = *oc;
4132 const XMLProperty* name = option->property("name");
4138 if (name->value() == "native-file-data-format") {
4139 const XMLProperty* value = option->property ("value");
4141 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4143 found_data_format = true;
4149 if (found_data_format) {
4154 return !(found_sr && found_data_format); // zero if they are both found
4157 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4158 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4161 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4165 SourcePathMap source_path_map;
4167 boost::shared_ptr<AudioFileSource> afs;
4172 Glib::Threads::Mutex::Lock lm (source_lock);
4174 cerr << " total sources = " << sources.size();
4176 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4177 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4183 if (fs->within_session()) {
4187 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4188 source_path_map[fs->path()].push_back (fs);
4190 SeveralFileSources v;
4192 source_path_map.insert (make_pair (fs->path(), v));
4198 cerr << " fsources = " << total << endl;
4200 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4202 /* tell caller where we are */
4204 string old_path = i->first;
4206 callback (n, total, old_path);
4208 cerr << old_path << endl;
4212 switch (i->second.front()->type()) {
4213 case DataType::AUDIO:
4214 new_path = new_audio_source_path_for_embedded (old_path);
4217 case DataType::MIDI:
4218 /* XXX not implemented yet */
4222 if (new_path.empty()) {
4226 cerr << "Move " << old_path << " => " << new_path << endl;
4228 if (!copy_file (old_path, new_path)) {
4229 cerr << "failed !\n";
4233 /* make sure we stop looking in the external
4234 dir/folder. Remember, this is an all-or-nothing
4235 operations, it doesn't merge just some files.
4237 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4239 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4240 (*f)->set_path (new_path);
4245 save_state ("", false, false);
4251 bool accept_all_files (string const &, void *)
4257 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4259 /* 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.
4264 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4266 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4268 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4270 v.push_back (new_session_folder); /* full path */
4271 v.push_back (interchange_dir_name);
4272 v.push_back (new_session_path); /* just one directory/folder */
4273 v.push_back (typedir);
4274 v.push_back (Glib::path_get_basename (old_path));
4276 return Glib::build_filename (v);
4280 Session::save_as (SaveAs& saveas)
4282 vector<string> files;
4283 string current_folder = Glib::path_get_dirname (_path);
4284 string new_folder = legalize_for_path (saveas.new_name);
4285 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4286 int64_t total_bytes = 0;
4290 int32_t internal_file_cnt = 0;
4292 vector<string> do_not_copy_extensions;
4293 do_not_copy_extensions.push_back (statefile_suffix);
4294 do_not_copy_extensions.push_back (pending_suffix);
4295 do_not_copy_extensions.push_back (backup_suffix);
4296 do_not_copy_extensions.push_back (temp_suffix);
4297 do_not_copy_extensions.push_back (history_suffix);
4299 /* get total size */
4301 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4303 /* need to clear this because
4304 * find_files_matching_filter() is cumulative
4309 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4311 all += files.size();
4313 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4315 g_stat ((*i).c_str(), &gsb);
4316 total_bytes += gsb.st_size;
4320 /* save old values so we can switch back if we are not switching to the new session */
4322 string old_path = _path;
4323 string old_name = _name;
4324 string old_snapshot = _current_snapshot_name;
4325 string old_sd = _session_dir->root_path();
4326 vector<string> old_search_path[DataType::num_types];
4327 string old_config_search_path[DataType::num_types];
4329 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4330 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4331 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4332 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4334 /* switch session directory */
4336 (*_session_dir) = to_dir;
4338 /* create new tree */
4340 if (!_session_dir->create()) {
4341 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4346 /* copy all relevant files. Find each location in session_dirs,
4347 * and copy files from there to target.
4350 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4352 /* need to clear this because
4353 * find_files_matching_filter() is cumulative
4358 const size_t prefix_len = (*sd).path.size();
4360 /* Work just on the files within this session dir */
4362 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4364 /* add dir separator to protect against collisions with
4365 * track names (e.g. track named "audiofiles" or
4369 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4370 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4371 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4373 /* copy all the files. Handling is different for media files
4374 than others because of the *silly* subtree we have below the interchange
4375 folder. That really was a bad idea, but I'm not fixing it as part of
4376 implementing ::save_as().
4379 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4381 std::string from = *i;
4384 string filename = Glib::path_get_basename (from);
4385 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4386 if (filename == ".DS_STORE") {
4391 if (from.find (audiofile_dir_string) != string::npos) {
4393 /* audio file: only copy if asked */
4395 if (saveas.include_media && saveas.copy_media) {
4397 string to = make_new_media_path (*i, to_dir, new_folder);
4399 info << "media file copying from " << from << " to " << to << endmsg;
4401 if (!copy_file (from, to)) {
4402 throw Glib::FileError (Glib::FileError::IO_ERROR,
4403 string_compose(_("\ncopying \"%1\" failed !"), from));
4407 /* we found media files inside the session folder */
4409 internal_file_cnt++;
4411 } else if (from.find (midifile_dir_string) != string::npos) {
4413 /* midi file: always copy unless
4414 * creating an empty new session
4417 if (saveas.include_media) {
4419 string to = make_new_media_path (*i, to_dir, new_folder);
4421 info << "media file copying from " << from << " to " << to << endmsg;
4423 if (!copy_file (from, to)) {
4424 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4428 /* we found media files inside the session folder */
4430 internal_file_cnt++;
4432 } else if (from.find (analysis_dir_string) != string::npos) {
4434 /* make sure analysis dir exists in
4435 * new session folder, but we're not
4436 * copying analysis files here, see
4440 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4445 /* normal non-media file. Don't copy state, history, etc.
4448 bool do_copy = true;
4450 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4451 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4452 /* end of filename matches extension, do not copy file */
4458 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4459 /* don't copy peakfiles if
4460 * we're not copying media
4466 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4468 info << "attempting to make directory/folder " << to << endmsg;
4470 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4471 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4474 info << "attempting to copy " << from << " to " << to << endmsg;
4476 if (!copy_file (from, to)) {
4477 throw Glib::FileError (Glib::FileError::IO_ERROR,
4478 string_compose(_("\ncopying \"%1\" failed !"), from));
4483 /* measure file size even if we're not going to copy so that our Progress
4484 signals are correct, since we included these do-not-copy files
4485 in the computation of the total size and file count.
4489 g_stat (from.c_str(), &gsb);
4490 copied += gsb.st_size;
4493 double fraction = (double) copied / total_bytes;
4495 bool keep_going = true;
4497 if (saveas.copy_media) {
4499 /* no need or expectation of this if
4500 * media is not being copied, because
4501 * it will be fast(ish).
4504 /* tell someone "X percent, file M of N"; M is one-based */
4506 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4514 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4520 /* copy optional folders, if any */
4522 string old = plugins_dir ();
4523 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4524 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4525 copy_files (old, newdir);
4528 old = externals_dir ();
4529 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4530 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4531 copy_files (old, newdir);
4534 old = automation_dir ();
4535 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4536 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4537 copy_files (old, newdir);
4540 if (saveas.include_media) {
4542 if (saveas.copy_media) {
4543 #ifndef PLATFORM_WINDOWS
4544 /* There are problems with analysis files on
4545 * Windows, because they used a colon in their
4546 * names as late as 4.0. Colons are not legal
4547 * under Windows even if NTFS allows them.
4549 * This is a tricky problem to solve so for
4550 * just don't copy these files. They will be
4551 * regenerated as-needed anyway, subject to the
4552 * existing issue that the filenames will be
4553 * rejected by Windows, which is a separate
4554 * problem (though related).
4557 /* only needed if we are copying media, since the
4558 * analysis data refers to media data
4561 old = analysis_dir ();
4562 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4563 string newdir = Glib::build_filename (to_dir, "analysis");
4564 copy_files (old, newdir);
4566 #endif /* PLATFORM_WINDOWS */
4572 _current_snapshot_name = saveas.new_name;
4573 _name = saveas.new_name;
4575 if (saveas.include_media && !saveas.copy_media) {
4577 /* reset search paths of the new session (which we're pretending to be right now) to
4578 include the original session search path, so we can still find all audio.
4581 if (internal_file_cnt) {
4582 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4583 ensure_search_path_includes (*s, DataType::AUDIO);
4584 cerr << "be sure to include " << *s << " for audio" << endl;
4587 /* we do not do this for MIDI because we copy
4588 all MIDI files if saveas.include_media is
4594 bool was_dirty = dirty ();
4596 save_state ("", false, false, !saveas.include_media);
4597 save_default_options ();
4599 if (saveas.copy_media && saveas.copy_external) {
4600 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4601 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4605 saveas.final_session_folder_name = _path;
4607 store_recent_sessions (_name, _path);
4609 if (!saveas.switch_to) {
4611 /* switch back to the way things were */
4615 _current_snapshot_name = old_snapshot;
4617 (*_session_dir) = old_sd;
4623 if (internal_file_cnt) {
4624 /* reset these to their original values */
4625 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4626 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4631 /* prune session dirs, and update disk space statistics
4636 session_dirs.clear ();
4637 session_dirs.push_back (sp);
4638 refresh_disk_space ();
4640 /* ensure that all existing tracks reset their current capture source paths
4642 reset_write_sources (true, true);
4644 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4645 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4648 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4649 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4655 if (fs->within_session()) {
4656 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4657 fs->set_path (newpath);
4662 } catch (Glib::FileError& e) {
4664 saveas.failure_message = e.what();
4666 /* recursively remove all the directories */
4668 remove_directory (to_dir);
4676 saveas.failure_message = _("unknown reason");
4678 /* recursively remove all the directories */
4680 remove_directory (to_dir);