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 */
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include <pbd/gstdio_compat.h>
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/boost_debug.h"
66 #include "pbd/basename.h"
67 #include "pbd/controllable_descriptor.h"
68 #include "pbd/debug.h"
69 #include "pbd/enumwriter.h"
70 #include "pbd/error.h"
71 #include "pbd/file_utils.h"
72 #include "pbd/pathexpand.h"
73 #include "pbd/pthread_utils.h"
74 #include "pbd/stacktrace.h"
75 #include "pbd/convert.h"
76 #include "pbd/localtime_r.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/automation_control.h"
86 #include "ardour/butler.h"
87 #include "ardour/control_protocol_manager.h"
88 #include "ardour/directory_names.h"
89 #include "ardour/filename_extensions.h"
90 #include "ardour/graph.h"
91 #include "ardour/location.h"
92 #include "ardour/midi_model.h"
93 #include "ardour/midi_patch_manager.h"
94 #include "ardour/midi_region.h"
95 #include "ardour/midi_scene_changer.h"
96 #include "ardour/midi_source.h"
97 #include "ardour/midi_track.h"
98 #include "ardour/pannable.h"
99 #include "ardour/playlist_factory.h"
100 #include "ardour/playlist_source.h"
101 #include "ardour/port.h"
102 #include "ardour/processor.h"
103 #include "ardour/profile.h"
104 #include "ardour/proxy_controllable.h"
105 #include "ardour/recent_sessions.h"
106 #include "ardour/region_factory.h"
107 #include "ardour/route_group.h"
108 #include "ardour/send.h"
109 #include "ardour/session.h"
110 #include "ardour/session_directory.h"
111 #include "ardour/session_metadata.h"
112 #include "ardour/session_playlists.h"
113 #include "ardour/session_state_utils.h"
114 #include "ardour/silentfilesource.h"
115 #include "ardour/sndfilesource.h"
116 #include "ardour/source_factory.h"
117 #include "ardour/speakers.h"
118 #include "ardour/template_utils.h"
119 #include "ardour/tempo.h"
120 #include "ardour/ticker.h"
121 #include "ardour/user_bundle.h"
123 #include "control_protocol/control_protocol.h"
129 using namespace ARDOUR;
132 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
135 Session::pre_engine_init (string fullpath)
137 if (fullpath.empty()) {
139 throw failed_constructor();
142 /* discover canonical fullpath */
144 _path = canonical_path(fullpath);
147 if (Profile->get_trx() ) {
148 // Waves TracksLive has a usecase of session replacement with a new one.
149 // We should check session state file (<session_name>.ardour) existance
150 // to determine if the session is new or not
152 string full_session_name = Glib::build_filename( fullpath, _name );
153 full_session_name += statefile_suffix;
155 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
157 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
160 /* finish initialization that can't be done in a normal C++ constructor
164 timerclear (&last_mmc_step);
165 g_atomic_int_set (&processing_prohibited, 0);
166 g_atomic_int_set (&_record_status, Disabled);
167 g_atomic_int_set (&_playback_load, 100);
168 g_atomic_int_set (&_capture_load, 100);
170 _all_route_group->set_active (true, this);
171 interpolation.add_channel_to (0, 0);
173 if (config.get_use_video_sync()) {
174 waiting_for_sync_offset = true;
176 waiting_for_sync_offset = false;
179 last_rr_session_dir = session_dirs.begin();
181 set_history_depth (Config->get_history_depth());
183 /* default: assume simple stereo speaker configuration */
185 _speakers->setup_default_speakers (2);
187 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
188 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
189 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
190 add_controllable (_solo_cut_control);
192 /* These are all static "per-class" signals */
194 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
195 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
196 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
197 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
198 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
200 /* stop IO objects from doing stuff until we're ready for them */
202 Delivery::disable_panners ();
203 IO::disable_connecting ();
207 Session::post_engine_init ()
209 BootMessage (_("Set block size and sample rate"));
211 set_block_size (_engine.samples_per_cycle());
212 set_frame_rate (_engine.sample_rate());
214 BootMessage (_("Using configuration"));
216 _midi_ports = new MidiPortManager;
218 MIDISceneChanger* msc;
220 _scene_changer = msc = new MIDISceneChanger (*this);
221 msc->set_input_port (scene_input_port());
222 msc->set_output_port (scene_out());
224 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
225 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
227 setup_midi_machine_control ();
229 if (_butler->start_thread()) {
233 if (start_midi_thread ()) {
237 setup_click_sounds (0);
238 setup_midi_control ();
240 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
241 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
244 /* tempo map requires sample rate knowledge */
247 _tempo_map = new TempoMap (_current_frame_rate);
248 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
250 /* MidiClock requires a tempo map */
252 midi_clock = new MidiClockTicker ();
253 midi_clock->set_session (this);
255 /* crossfades require sample rate knowledge */
257 SndFileSource::setup_standard_crossfades (*this, frame_rate());
258 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
260 AudioDiskstream::allocate_working_buffers();
261 refresh_disk_space ();
263 /* we're finally ready to call set_state() ... all objects have
264 * been created, the engine is running.
268 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
272 // set_state() will call setup_raid_path(), but if it's a new session we need
273 // to call setup_raid_path() here.
274 setup_raid_path (_path);
279 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
280 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
282 Config->map_parameters (ff);
283 config.map_parameters (ft);
284 _butler->map_parameters ();
286 /* Reset all panners */
288 Delivery::reset_panners ();
290 /* this will cause the CPM to instantiate any protocols that are in use
291 * (or mandatory), which will pass it this Session, and then call
292 * set_state() on each instantiated protocol to match stored state.
295 ControlProtocolManager::instance().set_session (this);
297 /* This must be done after the ControlProtocolManager set_session above,
298 as it will set states for ports which the ControlProtocolManager creates.
301 // XXX set state of MIDI::Port's
302 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
304 /* And this must be done after the MIDI::Manager::set_port_states as
305 * it will try to make connections whose details are loaded by set_port_states.
310 /* Let control protocols know that we are now all connected, so they
311 * could start talking to surfaces if they want to.
314 ControlProtocolManager::instance().midi_connectivity_established ();
316 if (_is_new && !no_auto_connect()) {
317 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
318 auto_connect_master_bus ();
321 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
323 /* update latencies */
325 initialize_latencies ();
327 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
328 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
329 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
331 } catch (AudioEngine::PortRegistrationFailure& err) {
332 /* handle this one in a different way than all others, so that its clear what happened */
333 error << err.what() << endmsg;
339 BootMessage (_("Reset Remote Controls"));
341 // send_full_time_code (0);
342 _engine.transport_locate (0);
344 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
345 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
347 MIDI::Name::MidiPatchManager::instance().set_session (this);
350 /* initial program change will be delivered later; see ::config_changed() */
352 _state_of_the_state = Clean;
354 Port::set_connecting_blocked (false);
356 DirtyChanged (); /* EMIT SIGNAL */
360 } else if (state_was_pending) {
362 remove_pending_capture_state ();
363 state_was_pending = false;
366 /* Now, finally, we can fill the playback buffers */
368 BootMessage (_("Filling playback buffers"));
370 boost::shared_ptr<RouteList> rl = routes.reader();
371 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
372 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
373 if (trk && !trk->hidden()) {
374 trk->seek (_transport_frame, true);
382 Session::session_loaded ()
386 _state_of_the_state = Clean;
388 DirtyChanged (); /* EMIT SIGNAL */
392 } else if (state_was_pending) {
394 remove_pending_capture_state ();
395 state_was_pending = false;
398 /* Now, finally, we can fill the playback buffers */
400 BootMessage (_("Filling playback buffers"));
401 force_locate (_transport_frame, false);
405 Session::raid_path () const
407 Searchpath raid_search_path;
409 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
410 raid_search_path += (*i).path;
413 return raid_search_path.to_string ();
417 Session::setup_raid_path (string path)
426 session_dirs.clear ();
428 Searchpath search_path(path);
429 Searchpath sound_search_path;
430 Searchpath midi_search_path;
432 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
434 sp.blocks = 0; // not needed
435 session_dirs.push_back (sp);
437 SessionDirectory sdir(sp.path);
439 sound_search_path += sdir.sound_path ();
440 midi_search_path += sdir.midi_path ();
443 // reset the round-robin soundfile path thingie
444 last_rr_session_dir = session_dirs.begin();
448 Session::path_is_within_session (const std::string& path)
450 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
451 if (PBD::path_is_within (i->path, path)) {
459 Session::ensure_subdirs ()
463 dir = session_directory().peak_path();
465 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
466 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
470 dir = session_directory().sound_path();
472 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
473 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
477 dir = session_directory().midi_path();
479 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
480 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
484 dir = session_directory().dead_path();
486 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
487 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
491 dir = session_directory().export_path();
493 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
494 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
498 dir = analysis_dir ();
500 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
501 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
505 dir = plugins_dir ();
507 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
508 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
512 dir = externals_dir ();
514 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
515 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
522 /** @param session_template directory containing session template, or empty.
523 * Caller must not hold process lock.
526 Session::create (const string& session_template, BusProfile* bus_profile)
528 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
529 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
533 if (ensure_subdirs ()) {
537 _writable = exists_and_writable (_path);
539 if (!session_template.empty()) {
540 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
542 FILE* in = g_fopen (in_path.c_str(), "rb");
545 /* no need to call legalize_for_path() since the string
546 * in session_template is already a legal path name
548 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
550 FILE* out = g_fopen (out_path.c_str(), "wb");
554 stringstream new_session;
557 size_t charsRead = fread (buf, sizeof(char), 1024, in);
560 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
565 if (charsRead == 0) {
568 new_session.write (buf, charsRead);
572 string file_contents = new_session.str();
573 size_t writeSize = file_contents.length();
574 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
575 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
583 if (!ARDOUR::Profile->get_trx()) {
584 /* Copy plugin state files from template to new session */
585 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
586 copy_recurse (template_plugins, plugins_dir ());
592 error << string_compose (_("Could not open %1 for writing session template"), out_path)
599 error << string_compose (_("Could not open session template %1 for reading"), in_path)
606 if (Profile->get_trx()) {
608 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
609 Remember that this is a brand new session. Sessions
610 loaded from saved state will get this range from the saved state.
613 set_session_range_location (0, 0);
615 /* Initial loop location, from absolute zero, length 10 seconds */
617 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
618 _locations->add (loc, true);
619 set_auto_loop_location (loc);
622 _state_of_the_state = Clean;
624 /* set up Master Out and Control Out if necessary */
629 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
631 // Waves Tracks: always create master bus for Tracks
632 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
633 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
637 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
638 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
641 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
642 r->input()->ensure_io (count, false, this);
643 r->output()->ensure_io (count, false, this);
649 /* prohibit auto-connect to master, because there isn't one */
650 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
654 add_routes (rl, false, false, false);
657 // Waves Tracks: Skip this. Always use autoconnection for Tracks
658 if (!ARDOUR::Profile->get_trx()) {
660 /* this allows the user to override settings with an environment variable.
663 if (no_auto_connect()) {
664 bus_profile->input_ac = AutoConnectOption (0);
665 bus_profile->output_ac = AutoConnectOption (0);
668 Config->set_input_auto_connect (bus_profile->input_ac);
669 Config->set_output_auto_connect (bus_profile->output_ac);
673 if (Config->get_use_monitor_bus() && bus_profile) {
674 add_monitor_section ();
681 Session::maybe_write_autosave()
683 if (dirty() && record_status() != Recording) {
684 save_state("", true);
689 Session::remove_pending_capture_state ()
691 std::string pending_state_file_path(_session_dir->root_path());
693 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
695 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
697 if (g_remove (pending_state_file_path.c_str()) != 0) {
698 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
699 pending_state_file_path, g_strerror (errno)) << endmsg;
703 /** Rename a state file.
704 * @param old_name Old snapshot name.
705 * @param new_name New snapshot name.
708 Session::rename_state (string old_name, string new_name)
710 if (old_name == _current_snapshot_name || old_name == _name) {
711 /* refuse to rename the current snapshot or the "main" one */
715 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
716 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
718 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
719 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
721 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
722 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
723 old_name, new_name, g_strerror(errno)) << endmsg;
727 /** Remove a state file.
728 * @param snapshot_name Snapshot name.
731 Session::remove_state (string snapshot_name)
733 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
734 // refuse to remove the current snapshot or the "main" one
738 std::string xml_path(_session_dir->root_path());
740 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
742 if (!create_backup_file (xml_path)) {
743 // don't remove it if a backup can't be made
744 // create_backup_file will log the error.
749 if (g_remove (xml_path.c_str()) != 0) {
750 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
751 xml_path, g_strerror (errno)) << endmsg;
755 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
757 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
760 std::string xml_path(_session_dir->root_path());
762 /* prevent concurrent saves from different threads */
764 Glib::Threads::Mutex::Lock lm (save_state_lock);
766 if (!_writable || (_state_of_the_state & CannotSave)) {
770 if (g_atomic_int_get(&_suspend_save)) {
774 _save_queued = false;
776 if (!_engine.connected ()) {
777 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
783 /* tell sources we're saving first, in case they write out to a new file
784 * which should be saved with the state rather than the old one */
785 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
787 i->second->session_saved();
788 } catch (Evoral::SMF::FileError& e) {
789 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
793 SessionSaveUnderway (); /* EMIT SIGNAL */
796 tree.set_root (&get_template());
798 tree.set_root (&get_state());
801 if (snapshot_name.empty()) {
802 snapshot_name = _current_snapshot_name;
803 } else if (switch_to_snapshot) {
804 _current_snapshot_name = snapshot_name;
809 /* proper save: use statefile_suffix (.ardour in English) */
811 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
813 /* make a backup copy of the old file */
815 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
816 // create_backup_file will log the error
822 /* pending save: use pending_suffix (.pending in English) */
823 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
826 std::string tmp_path(_session_dir->root_path());
827 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
829 cerr << "actually writing state to " << tmp_path << endl;
831 if (!tree.write (tmp_path)) {
832 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
833 if (g_remove (tmp_path.c_str()) != 0) {
834 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
835 tmp_path, g_strerror (errno)) << endmsg;
841 cerr << "renaming state to " << xml_path << endl;
843 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
844 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
845 tmp_path, xml_path, g_strerror(errno)) << endmsg;
846 if (g_remove (tmp_path.c_str()) != 0) {
847 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
848 tmp_path, g_strerror (errno)) << endmsg;
856 save_history (snapshot_name);
858 bool was_dirty = dirty();
860 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
863 DirtyChanged (); /* EMIT SIGNAL */
866 StateSaved (snapshot_name); /* EMIT SIGNAL */
873 Session::restore_state (string snapshot_name)
875 if (load_state (snapshot_name) == 0) {
876 set_state (*state_tree->root(), Stateful::loading_state_version);
883 Session::load_state (string snapshot_name)
888 state_was_pending = false;
890 /* check for leftover pending state from a crashed capture attempt */
892 std::string xmlpath(_session_dir->root_path());
893 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
895 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
897 /* there is pending state from a crashed capture attempt */
899 boost::optional<int> r = AskAboutPendingState();
900 if (r.get_value_or (1)) {
901 state_was_pending = true;
905 if (!state_was_pending) {
906 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
909 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
910 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
911 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
912 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
917 state_tree = new XMLTree;
921 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
923 if (!state_tree->read (xmlpath)) {
924 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
930 XMLNode& root (*state_tree->root());
932 if (root.name() != X_("Session")) {
933 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
939 const XMLProperty* prop;
941 if ((prop = root.property ("version")) == 0) {
942 /* no version implies very old version of Ardour */
943 Stateful::loading_state_version = 1000;
945 if (prop->value().find ('.') != string::npos) {
946 /* old school version format */
947 if (prop->value()[0] == '2') {
948 Stateful::loading_state_version = 2000;
950 Stateful::loading_state_version = 3000;
953 Stateful::loading_state_version = atoi (prop->value());
957 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
959 std::string backup_path(_session_dir->root_path());
960 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
961 backup_path = Glib::build_filename (backup_path, backup_filename);
963 // only create a backup for a given statefile version once
965 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
967 VersionMismatch (xmlpath, backup_path);
969 if (!copy_file (xmlpath, backup_path)) {;
979 Session::load_options (const XMLNode& node)
981 LocaleGuard lg (X_("C"));
982 config.set_variables (node);
987 Session::save_default_options ()
989 return config.save_state();
999 Session::get_template()
1001 /* if we don't disable rec-enable, diskstreams
1002 will believe they need to store their capture
1003 sources in their state node.
1006 disable_record (false);
1008 return state(false);
1012 Session::state (bool full_state)
1014 XMLNode* node = new XMLNode("Session");
1018 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1019 node->add_property("version", buf);
1021 /* store configuration settings */
1025 node->add_property ("name", _name);
1026 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
1027 node->add_property ("sample-rate", buf);
1029 if (session_dirs.size() > 1) {
1033 vector<space_and_path>::iterator i = session_dirs.begin();
1034 vector<space_and_path>::iterator next;
1036 ++i; /* skip the first one */
1040 while (i != session_dirs.end()) {
1044 if (next != session_dirs.end()) {
1045 p += G_SEARCHPATH_SEPARATOR;
1054 child = node->add_child ("Path");
1055 child->add_content (p);
1059 /* save the ID counter */
1061 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1062 node->add_property ("id-counter", buf);
1064 /* save the event ID counter */
1066 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1067 node->add_property ("event-counter", buf);
1069 /* various options */
1071 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1072 if (!midi_port_nodes.empty()) {
1073 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1074 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1075 midi_port_stuff->add_child_nocopy (**n);
1077 node->add_child_nocopy (*midi_port_stuff);
1080 node->add_child_nocopy (config.get_variables ());
1082 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1084 child = node->add_child ("Sources");
1087 Glib::Threads::Mutex::Lock sl (source_lock);
1089 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1091 /* Don't save information about non-file Sources, or
1092 * about non-destructive file sources that are empty
1093 * and unused by any regions.
1096 boost::shared_ptr<FileSource> fs;
1098 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1100 if (!fs->destructive()) {
1101 if (fs->empty() && !fs->used()) {
1106 child->add_child_nocopy (siter->second->get_state());
1111 child = node->add_child ("Regions");
1114 Glib::Threads::Mutex::Lock rl (region_lock);
1115 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1116 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1117 boost::shared_ptr<Region> r = i->second;
1118 /* only store regions not attached to playlists */
1119 if (r->playlist() == 0) {
1120 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1121 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1123 child->add_child_nocopy (r->get_state ());
1128 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1130 if (!cassocs.empty()) {
1131 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1133 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1135 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1136 i->first->id().print (buf, sizeof (buf));
1137 can->add_property (X_("copy"), buf);
1138 i->second->id().print (buf, sizeof (buf));
1139 can->add_property (X_("original"), buf);
1140 ca->add_child_nocopy (*can);
1150 node->add_child_nocopy (_locations->get_state());
1153 Locations loc (*this);
1154 // for a template, just create a new Locations, populate it
1155 // with the default start and end, and get the state for that.
1156 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1157 range->set (max_framepos, 0);
1159 XMLNode& locations_state = loc.get_state();
1161 if (ARDOUR::Profile->get_trx() && _locations) {
1162 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1163 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1164 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1165 locations_state.add_child_nocopy ((*i)->get_state ());
1169 node->add_child_nocopy (locations_state);
1172 child = node->add_child ("Bundles");
1174 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1175 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1176 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1178 child->add_child_nocopy (b->get_state());
1183 child = node->add_child ("Routes");
1185 boost::shared_ptr<RouteList> r = routes.reader ();
1187 RoutePublicOrderSorter cmp;
1188 RouteList public_order (*r);
1189 public_order.sort (cmp);
1191 /* the sort should have put control outs first */
1194 assert (_monitor_out == public_order.front());
1197 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1198 if (!(*i)->is_auditioner()) {
1200 child->add_child_nocopy ((*i)->get_state());
1202 child->add_child_nocopy ((*i)->get_template());
1208 playlists->add_state (node, full_state);
1210 child = node->add_child ("RouteGroups");
1211 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1212 child->add_child_nocopy ((*i)->get_state());
1216 XMLNode* gain_child = node->add_child ("Click");
1217 gain_child->add_child_nocopy (_click_io->state (full_state));
1218 gain_child->add_child_nocopy (_click_gain->state (full_state));
1222 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1223 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1227 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1228 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1231 node->add_child_nocopy (_speakers->get_state());
1232 node->add_child_nocopy (_tempo_map->get_state());
1233 node->add_child_nocopy (get_control_protocol_state());
1236 node->add_child_copy (*_extra_xml);
1243 Session::get_control_protocol_state ()
1245 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1246 return cpm.get_state();
1250 Session::set_state (const XMLNode& node, int version)
1254 const XMLProperty* prop;
1257 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1259 if (node.name() != X_("Session")) {
1260 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1264 if ((prop = node.property ("name")) != 0) {
1265 _name = prop->value ();
1268 if ((prop = node.property (X_("sample-rate"))) != 0) {
1270 _nominal_frame_rate = atoi (prop->value());
1272 if (_nominal_frame_rate != _current_frame_rate) {
1273 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1274 if (r.get_value_or (0)) {
1280 setup_raid_path(_session_dir->root_path());
1282 if ((prop = node.property (X_("id-counter"))) != 0) {
1284 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1285 ID::init_counter (x);
1287 /* old sessions used a timebased counter, so fake
1288 the startup ID counter based on a standard
1293 ID::init_counter (now);
1296 if ((prop = node.property (X_("event-counter"))) != 0) {
1297 Evoral::init_event_id_counter (atoi (prop->value()));
1301 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1302 _midi_ports->set_midi_port_states (child->children());
1305 IO::disable_connecting ();
1307 Stateful::save_extra_xml (node);
1309 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1310 load_options (*child);
1311 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1312 load_options (*child);
1314 error << _("Session: XML state has no options section") << endmsg;
1317 if (version >= 3000) {
1318 if ((child = find_named_node (node, "Metadata")) == 0) {
1319 warning << _("Session: XML state has no metadata section") << endmsg;
1320 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1325 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1326 _speakers->set_state (*child, version);
1329 if ((child = find_named_node (node, "Sources")) == 0) {
1330 error << _("Session: XML state has no sources section") << endmsg;
1332 } else if (load_sources (*child)) {
1336 if ((child = find_named_node (node, "TempoMap")) == 0) {
1337 error << _("Session: XML state has no Tempo Map section") << endmsg;
1339 } else if (_tempo_map->set_state (*child, version)) {
1343 if ((child = find_named_node (node, "Locations")) == 0) {
1344 error << _("Session: XML state has no locations section") << endmsg;
1346 } else if (_locations->set_state (*child, version)) {
1350 locations_changed ();
1352 if (_session_range_location) {
1353 AudioFileSource::set_header_position_offset (_session_range_location->start());
1356 if ((child = find_named_node (node, "Regions")) == 0) {
1357 error << _("Session: XML state has no Regions section") << endmsg;
1359 } else if (load_regions (*child)) {
1363 if ((child = find_named_node (node, "Playlists")) == 0) {
1364 error << _("Session: XML state has no playlists section") << endmsg;
1366 } else if (playlists->load (*this, *child)) {
1370 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1372 } else if (playlists->load_unused (*this, *child)) {
1376 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1377 if (load_compounds (*child)) {
1382 if (version >= 3000) {
1383 if ((child = find_named_node (node, "Bundles")) == 0) {
1384 warning << _("Session: XML state has no bundles section") << endmsg;
1387 /* We can't load Bundles yet as they need to be able
1388 to convert from port names to Port objects, which can't happen until
1390 _bundle_xml_node = new XMLNode (*child);
1394 if (version < 3000) {
1395 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1396 error << _("Session: XML state has no diskstreams section") << endmsg;
1398 } else if (load_diskstreams_2X (*child, version)) {
1403 if ((child = find_named_node (node, "Routes")) == 0) {
1404 error << _("Session: XML state has no routes section") << endmsg;
1406 } else if (load_routes (*child, version)) {
1410 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1411 _diskstreams_2X.clear ();
1413 if (version >= 3000) {
1415 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1416 error << _("Session: XML state has no route groups section") << endmsg;
1418 } else if (load_route_groups (*child, version)) {
1422 } else if (version < 3000) {
1424 if ((child = find_named_node (node, "EditGroups")) == 0) {
1425 error << _("Session: XML state has no edit groups section") << endmsg;
1427 } else if (load_route_groups (*child, version)) {
1431 if ((child = find_named_node (node, "MixGroups")) == 0) {
1432 error << _("Session: XML state has no mix groups section") << endmsg;
1434 } else if (load_route_groups (*child, version)) {
1439 if ((child = find_named_node (node, "Click")) == 0) {
1440 warning << _("Session: XML state has no click section") << endmsg;
1441 } else if (_click_io) {
1442 setup_click_state (&node);
1445 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1446 ControlProtocolManager::instance().set_state (*child, version);
1449 update_route_record_state ();
1451 /* here beginneth the second phase ... */
1453 StateReady (); /* EMIT SIGNAL */
1466 Session::load_routes (const XMLNode& node, int version)
1469 XMLNodeConstIterator niter;
1470 RouteList new_routes;
1472 nlist = node.children();
1476 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1478 boost::shared_ptr<Route> route;
1479 if (version < 3000) {
1480 route = XMLRouteFactory_2X (**niter, version);
1482 route = XMLRouteFactory (**niter, version);
1486 error << _("Session: cannot create Route from XML description.") << endmsg;
1490 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1492 new_routes.push_back (route);
1495 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1497 add_routes (new_routes, false, false, false);
1499 BootMessage (_("Finished adding tracks/busses"));
1504 boost::shared_ptr<Route>
1505 Session::XMLRouteFactory (const XMLNode& node, int version)
1507 boost::shared_ptr<Route> ret;
1509 if (node.name() != "Route") {
1513 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1515 DataType type = DataType::AUDIO;
1516 const XMLProperty* prop = node.property("default-type");
1519 type = DataType (prop->value());
1522 assert (type != DataType::NIL);
1526 boost::shared_ptr<Track> track;
1528 if (type == DataType::AUDIO) {
1529 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1531 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1534 if (track->init()) {
1538 if (track->set_state (node, version)) {
1542 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1543 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1548 enum Route::Flag flags = Route::Flag(0);
1549 const XMLProperty* prop = node.property("flags");
1551 flags = Route::Flag (string_2_enum (prop->value(), flags));
1554 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1556 if (r->init () == 0 && r->set_state (node, version) == 0) {
1557 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1558 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1567 boost::shared_ptr<Route>
1568 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1570 boost::shared_ptr<Route> ret;
1572 if (node.name() != "Route") {
1576 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1578 ds_prop = node.property (X_("diskstream"));
1581 DataType type = DataType::AUDIO;
1582 const XMLProperty* prop = node.property("default-type");
1585 type = DataType (prop->value());
1588 assert (type != DataType::NIL);
1592 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1593 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1597 if (i == _diskstreams_2X.end()) {
1598 error << _("Could not find diskstream for route") << endmsg;
1599 return boost::shared_ptr<Route> ();
1602 boost::shared_ptr<Track> track;
1604 if (type == DataType::AUDIO) {
1605 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1607 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1610 if (track->init()) {
1614 if (track->set_state (node, version)) {
1618 track->set_diskstream (*i);
1620 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1621 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1626 enum Route::Flag flags = Route::Flag(0);
1627 const XMLProperty* prop = node.property("flags");
1629 flags = Route::Flag (string_2_enum (prop->value(), flags));
1632 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1634 if (r->init () == 0 && r->set_state (node, version) == 0) {
1635 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1636 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1646 Session::load_regions (const XMLNode& node)
1649 XMLNodeConstIterator niter;
1650 boost::shared_ptr<Region> region;
1652 nlist = node.children();
1656 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1657 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1658 error << _("Session: cannot create Region from XML description.");
1659 const XMLProperty *name = (**niter).property("name");
1662 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1673 Session::load_compounds (const XMLNode& node)
1675 XMLNodeList calist = node.children();
1676 XMLNodeConstIterator caiter;
1677 XMLProperty *caprop;
1679 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1680 XMLNode* ca = *caiter;
1684 if ((caprop = ca->property (X_("original"))) == 0) {
1687 orig_id = caprop->value();
1689 if ((caprop = ca->property (X_("copy"))) == 0) {
1692 copy_id = caprop->value();
1694 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1695 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1697 if (!orig || !copy) {
1698 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1704 RegionFactory::add_compound_association (orig, copy);
1711 Session::load_nested_sources (const XMLNode& node)
1714 XMLNodeConstIterator niter;
1716 nlist = node.children();
1718 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1719 if ((*niter)->name() == "Source") {
1721 /* it may already exist, so don't recreate it unnecessarily
1724 XMLProperty* prop = (*niter)->property (X_("id"));
1726 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1730 ID source_id (prop->value());
1732 if (!source_by_id (source_id)) {
1735 SourceFactory::create (*this, **niter, true);
1737 catch (failed_constructor& err) {
1738 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1745 boost::shared_ptr<Region>
1746 Session::XMLRegionFactory (const XMLNode& node, bool full)
1748 const XMLProperty* type = node.property("type");
1752 const XMLNodeList& nlist = node.children();
1754 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1755 XMLNode *child = (*niter);
1756 if (child->name() == "NestedSource") {
1757 load_nested_sources (*child);
1761 if (!type || type->value() == "audio") {
1762 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1763 } else if (type->value() == "midi") {
1764 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1767 } catch (failed_constructor& err) {
1768 return boost::shared_ptr<Region> ();
1771 return boost::shared_ptr<Region> ();
1774 boost::shared_ptr<AudioRegion>
1775 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1777 const XMLProperty* prop;
1778 boost::shared_ptr<Source> source;
1779 boost::shared_ptr<AudioSource> as;
1781 SourceList master_sources;
1782 uint32_t nchans = 1;
1785 if (node.name() != X_("Region")) {
1786 return boost::shared_ptr<AudioRegion>();
1789 if ((prop = node.property (X_("channels"))) != 0) {
1790 nchans = atoi (prop->value().c_str());
1793 if ((prop = node.property ("name")) == 0) {
1794 cerr << "no name for this region\n";
1798 if ((prop = node.property (X_("source-0"))) == 0) {
1799 if ((prop = node.property ("source")) == 0) {
1800 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1801 return boost::shared_ptr<AudioRegion>();
1805 PBD::ID s_id (prop->value());
1807 if ((source = source_by_id (s_id)) == 0) {
1808 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1809 return boost::shared_ptr<AudioRegion>();
1812 as = boost::dynamic_pointer_cast<AudioSource>(source);
1814 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1815 return boost::shared_ptr<AudioRegion>();
1818 sources.push_back (as);
1820 /* pickup other channels */
1822 for (uint32_t n=1; n < nchans; ++n) {
1823 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1824 if ((prop = node.property (buf)) != 0) {
1826 PBD::ID id2 (prop->value());
1828 if ((source = source_by_id (id2)) == 0) {
1829 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1830 return boost::shared_ptr<AudioRegion>();
1833 as = boost::dynamic_pointer_cast<AudioSource>(source);
1835 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1836 return boost::shared_ptr<AudioRegion>();
1838 sources.push_back (as);
1842 for (uint32_t n = 0; n < nchans; ++n) {
1843 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1844 if ((prop = node.property (buf)) != 0) {
1846 PBD::ID id2 (prop->value());
1848 if ((source = source_by_id (id2)) == 0) {
1849 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1850 return boost::shared_ptr<AudioRegion>();
1853 as = boost::dynamic_pointer_cast<AudioSource>(source);
1855 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1856 return boost::shared_ptr<AudioRegion>();
1858 master_sources.push_back (as);
1863 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1865 /* a final detail: this is the one and only place that we know how long missing files are */
1867 if (region->whole_file()) {
1868 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1869 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1871 sfp->set_length (region->length());
1876 if (!master_sources.empty()) {
1877 if (master_sources.size() != nchans) {
1878 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1880 region->set_master_sources (master_sources);
1888 catch (failed_constructor& err) {
1889 return boost::shared_ptr<AudioRegion>();
1893 boost::shared_ptr<MidiRegion>
1894 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1896 const XMLProperty* prop;
1897 boost::shared_ptr<Source> source;
1898 boost::shared_ptr<MidiSource> ms;
1901 if (node.name() != X_("Region")) {
1902 return boost::shared_ptr<MidiRegion>();
1905 if ((prop = node.property ("name")) == 0) {
1906 cerr << "no name for this region\n";
1910 if ((prop = node.property (X_("source-0"))) == 0) {
1911 if ((prop = node.property ("source")) == 0) {
1912 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1913 return boost::shared_ptr<MidiRegion>();
1917 PBD::ID s_id (prop->value());
1919 if ((source = source_by_id (s_id)) == 0) {
1920 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1921 return boost::shared_ptr<MidiRegion>();
1924 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1926 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1927 return boost::shared_ptr<MidiRegion>();
1930 sources.push_back (ms);
1933 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1934 /* a final detail: this is the one and only place that we know how long missing files are */
1936 if (region->whole_file()) {
1937 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1938 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1940 sfp->set_length (region->length());
1948 catch (failed_constructor& err) {
1949 return boost::shared_ptr<MidiRegion>();
1954 Session::get_sources_as_xml ()
1957 XMLNode* node = new XMLNode (X_("Sources"));
1958 Glib::Threads::Mutex::Lock lm (source_lock);
1960 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1961 node->add_child_nocopy (i->second->get_state());
1968 Session::reset_write_sources (bool mark_write_complete, bool force)
1970 boost::shared_ptr<RouteList> rl = routes.reader();
1971 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1972 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1974 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1975 tr->reset_write_sources(mark_write_complete, force);
1976 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1982 Session::load_sources (const XMLNode& node)
1985 XMLNodeConstIterator niter;
1986 boost::shared_ptr<Source> source; /* don't need this but it stops some
1987 * versions of gcc complaining about
1988 * discarded return values.
1991 nlist = node.children();
1995 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1998 if ((source = XMLSourceFactory (**niter)) == 0) {
1999 error << _("Session: cannot create Source from XML description.") << endmsg;
2002 } catch (MissingSource& err) {
2006 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2007 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2008 PROGRAM_NAME) << endmsg;
2012 if (!no_questions_about_missing_files) {
2013 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2018 switch (user_choice) {
2020 /* user added a new search location, so try again */
2025 /* user asked to quit the entire session load
2030 no_questions_about_missing_files = true;
2034 no_questions_about_missing_files = true;
2041 case DataType::AUDIO:
2042 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2045 case DataType::MIDI:
2046 /* The MIDI file is actually missing so
2047 * just create a new one in the same
2048 * location. Do not announce its
2052 if (!Glib::path_is_absolute (err.path)) {
2053 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2055 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2060 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2061 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2062 /* reset ID to match the missing one */
2063 source->set_id (**niter);
2064 /* Now we can announce it */
2065 SourceFactory::SourceCreated (source);
2076 boost::shared_ptr<Source>
2077 Session::XMLSourceFactory (const XMLNode& node)
2079 if (node.name() != "Source") {
2080 return boost::shared_ptr<Source>();
2084 /* note: do peak building in another thread when loading session state */
2085 return SourceFactory::create (*this, node, true);
2088 catch (failed_constructor& err) {
2089 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2090 return boost::shared_ptr<Source>();
2095 Session::save_template (string template_name)
2097 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2101 bool absolute_path = Glib::path_is_absolute (template_name);
2103 /* directory to put the template in */
2104 std::string template_dir_path;
2106 if (!absolute_path) {
2107 std::string user_template_dir(user_template_directory());
2109 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2110 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2111 user_template_dir, g_strerror (errno)) << endmsg;
2115 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2117 template_dir_path = template_name;
2120 if (!ARDOUR::Profile->get_trx()) {
2121 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2122 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2123 template_dir_path) << endmsg;
2127 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2128 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2129 template_dir_path, g_strerror (errno)) << endmsg;
2135 std::string template_file_path;
2137 if (ARDOUR::Profile->get_trx()) {
2138 template_file_path = template_name;
2140 if (absolute_path) {
2141 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2143 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2147 SessionSaveUnderway (); /* EMIT SIGNAL */
2151 tree.set_root (&get_template());
2152 if (!tree.write (template_file_path)) {
2153 error << _("template not saved") << endmsg;
2157 if (!ARDOUR::Profile->get_trx()) {
2158 /* copy plugin state directory */
2160 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2162 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2163 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2164 template_plugin_state_path, g_strerror (errno)) << endmsg;
2167 copy_files (plugins_dir(), template_plugin_state_path);
2170 store_recent_templates (template_file_path);
2176 Session::refresh_disk_space ()
2178 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2180 Glib::Threads::Mutex::Lock lm (space_lock);
2182 /* get freespace on every FS that is part of the session path */
2184 _total_free_4k_blocks = 0;
2185 _total_free_4k_blocks_uncertain = false;
2187 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2189 struct statfs statfsbuf;
2190 statfs (i->path.c_str(), &statfsbuf);
2192 double const scale = statfsbuf.f_bsize / 4096.0;
2194 /* See if this filesystem is read-only */
2195 struct statvfs statvfsbuf;
2196 statvfs (i->path.c_str(), &statvfsbuf);
2198 /* f_bavail can be 0 if it is undefined for whatever
2199 filesystem we are looking at; Samba shares mounted
2200 via GVFS are an example of this.
2202 if (statfsbuf.f_bavail == 0) {
2203 /* block count unknown */
2205 i->blocks_unknown = true;
2206 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2207 /* read-only filesystem */
2209 i->blocks_unknown = false;
2211 /* read/write filesystem with known space */
2212 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2213 i->blocks_unknown = false;
2216 _total_free_4k_blocks += i->blocks;
2217 if (i->blocks_unknown) {
2218 _total_free_4k_blocks_uncertain = true;
2221 #elif defined PLATFORM_WINDOWS
2222 vector<string> scanned_volumes;
2223 vector<string>::iterator j;
2224 vector<space_and_path>::iterator i;
2225 DWORD nSectorsPerCluster, nBytesPerSector,
2226 nFreeClusters, nTotalClusters;
2230 _total_free_4k_blocks = 0;
2232 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2233 strncpy (disk_drive, (*i).path.c_str(), 3);
2237 volume_found = false;
2238 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2240 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2241 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2242 i->blocks = (uint32_t)(nFreeBytes / 4096);
2244 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2245 if (0 == j->compare(disk_drive)) {
2246 volume_found = true;
2251 if (!volume_found) {
2252 scanned_volumes.push_back(disk_drive);
2253 _total_free_4k_blocks += i->blocks;
2258 if (0 == _total_free_4k_blocks) {
2259 strncpy (disk_drive, path().c_str(), 3);
2262 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2264 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2265 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2266 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2273 Session::get_best_session_directory_for_new_audio ()
2275 vector<space_and_path>::iterator i;
2276 string result = _session_dir->root_path();
2278 /* handle common case without system calls */
2280 if (session_dirs.size() == 1) {
2284 /* OK, here's the algorithm we're following here:
2286 We want to select which directory to use for
2287 the next file source to be created. Ideally,
2288 we'd like to use a round-robin process so as to
2289 get maximum performance benefits from splitting
2290 the files across multiple disks.
2292 However, in situations without much diskspace, an
2293 RR approach may end up filling up a filesystem
2294 with new files while others still have space.
2295 Its therefore important to pay some attention to
2296 the freespace in the filesystem holding each
2297 directory as well. However, if we did that by
2298 itself, we'd keep creating new files in the file
2299 system with the most space until it was as full
2300 as all others, thus negating any performance
2301 benefits of this RAID-1 like approach.
2303 So, we use a user-configurable space threshold. If
2304 there are at least 2 filesystems with more than this
2305 much space available, we use RR selection between them.
2306 If not, then we pick the filesystem with the most space.
2308 This gets a good balance between the two
2312 refresh_disk_space ();
2314 int free_enough = 0;
2316 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2317 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2322 if (free_enough >= 2) {
2323 /* use RR selection process, ensuring that the one
2327 i = last_rr_session_dir;
2330 if (++i == session_dirs.end()) {
2331 i = session_dirs.begin();
2334 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2335 SessionDirectory sdir(i->path);
2336 if (sdir.create ()) {
2338 last_rr_session_dir = i;
2343 } while (i != last_rr_session_dir);
2347 /* pick FS with the most freespace (and that
2348 seems to actually work ...)
2351 vector<space_and_path> sorted;
2352 space_and_path_ascending_cmp cmp;
2354 sorted = session_dirs;
2355 sort (sorted.begin(), sorted.end(), cmp);
2357 for (i = sorted.begin(); i != sorted.end(); ++i) {
2358 SessionDirectory sdir(i->path);
2359 if (sdir.create ()) {
2361 last_rr_session_dir = i;
2371 Session::automation_dir () const
2373 return Glib::build_filename (_path, automation_dir_name);
2377 Session::analysis_dir () const
2379 return Glib::build_filename (_path, analysis_dir_name);
2383 Session::plugins_dir () const
2385 return Glib::build_filename (_path, plugins_dir_name);
2389 Session::externals_dir () const
2391 return Glib::build_filename (_path, externals_dir_name);
2395 Session::load_bundles (XMLNode const & node)
2397 XMLNodeList nlist = node.children();
2398 XMLNodeConstIterator niter;
2402 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2403 if ((*niter)->name() == "InputBundle") {
2404 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2405 } else if ((*niter)->name() == "OutputBundle") {
2406 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2408 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2417 Session::load_route_groups (const XMLNode& node, int version)
2419 XMLNodeList nlist = node.children();
2420 XMLNodeConstIterator niter;
2424 if (version >= 3000) {
2426 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2427 if ((*niter)->name() == "RouteGroup") {
2428 RouteGroup* rg = new RouteGroup (*this, "");
2429 add_route_group (rg);
2430 rg->set_state (**niter, version);
2434 } else if (version < 3000) {
2436 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2437 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2438 RouteGroup* rg = new RouteGroup (*this, "");
2439 add_route_group (rg);
2440 rg->set_state (**niter, version);
2449 state_file_filter (const string &str, void* /*arg*/)
2451 return (str.length() > strlen(statefile_suffix) &&
2452 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2456 remove_end(string state)
2458 string statename(state);
2460 string::size_type start,end;
2461 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2462 statename = statename.substr (start+1);
2465 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2466 end = statename.length();
2469 return string(statename.substr (0, end));
2473 Session::possible_states (string path)
2475 vector<string> states;
2476 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2478 transform(states.begin(), states.end(), states.begin(), remove_end);
2480 sort (states.begin(), states.end());
2486 Session::possible_states () const
2488 return possible_states(_path);
2492 Session::add_route_group (RouteGroup* g)
2494 _route_groups.push_back (g);
2495 route_group_added (g); /* EMIT SIGNAL */
2497 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2498 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2499 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2505 Session::remove_route_group (RouteGroup& rg)
2507 list<RouteGroup*>::iterator i;
2509 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2510 _route_groups.erase (i);
2513 route_group_removed (); /* EMIT SIGNAL */
2517 /** Set a new order for our route groups, without adding or removing any.
2518 * @param groups Route group list in the new order.
2521 Session::reorder_route_groups (list<RouteGroup*> groups)
2523 _route_groups = groups;
2525 route_groups_reordered (); /* EMIT SIGNAL */
2531 Session::route_group_by_name (string name)
2533 list<RouteGroup *>::iterator i;
2535 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2536 if ((*i)->name() == name) {
2544 Session::all_route_group() const
2546 return *_all_route_group;
2550 Session::add_commands (vector<Command*> const & cmds)
2552 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2558 Session::add_command (Command* const cmd)
2560 assert (_current_trans);
2561 DEBUG_UNDO_HISTORY (
2562 string_compose ("Current Undo Transaction %1, adding command: %2",
2563 _current_trans->name (),
2565 _current_trans->add_command (cmd);
2568 Session::begin_reversible_command (const string& name)
2570 begin_reversible_command (g_quark_from_string (name.c_str ()));
2573 /** Begin a reversible command using a GQuark to identify it.
2574 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2575 * but there must be as many begin...()s as there are commit...()s.
2578 Session::begin_reversible_command (GQuark q)
2580 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2581 to hold all the commands that are committed. This keeps the order of
2582 commands correct in the history.
2585 if (_current_trans == 0) {
2586 DEBUG_UNDO_HISTORY (string_compose (
2587 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2589 /* start a new transaction */
2590 assert (_current_trans_quarks.empty ());
2591 _current_trans = new UndoTransaction();
2592 _current_trans->set_name (g_quark_to_string (q));
2594 DEBUG_UNDO_HISTORY (
2595 string_compose ("Begin Reversible Command, current transaction: %1",
2596 _current_trans->name ()));
2599 _current_trans_quarks.push_front (q);
2603 Session::abort_reversible_command ()
2605 if (_current_trans != 0) {
2606 DEBUG_UNDO_HISTORY (
2607 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2608 _current_trans->clear();
2609 delete _current_trans;
2611 _current_trans_quarks.clear();
2616 Session::commit_reversible_command (Command *cmd)
2618 assert (_current_trans);
2619 assert (!_current_trans_quarks.empty ());
2624 DEBUG_UNDO_HISTORY (
2625 string_compose ("Current Undo Transaction %1, adding command: %2",
2626 _current_trans->name (),
2628 _current_trans->add_command (cmd);
2631 DEBUG_UNDO_HISTORY (
2632 string_compose ("Commit Reversible Command, current transaction: %1",
2633 _current_trans->name ()));
2635 _current_trans_quarks.pop_front ();
2637 if (!_current_trans_quarks.empty ()) {
2638 DEBUG_UNDO_HISTORY (
2639 string_compose ("Commit Reversible Command, transaction is not "
2640 "top-level, current transaction: %1",
2641 _current_trans->name ()));
2642 /* the transaction we're committing is not the top-level one */
2646 if (_current_trans->empty()) {
2647 /* no commands were added to the transaction, so just get rid of it */
2648 DEBUG_UNDO_HISTORY (
2649 string_compose ("Commit Reversible Command, No commands were "
2650 "added to current transaction: %1",
2651 _current_trans->name ()));
2652 delete _current_trans;
2657 gettimeofday (&now, 0);
2658 _current_trans->set_timestamp (now);
2660 _history.add (_current_trans);
2665 accept_all_audio_files (const string& path, void* /*arg*/)
2667 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2671 if (!AudioFileSource::safe_audio_file_extension (path)) {
2679 accept_all_midi_files (const string& path, void* /*arg*/)
2681 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2685 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2686 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2687 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2691 accept_all_state_files (const string& path, void* /*arg*/)
2693 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2697 std::string const statefile_ext (statefile_suffix);
2698 if (path.length() >= statefile_ext.length()) {
2699 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2706 Session::find_all_sources (string path, set<string>& result)
2711 if (!tree.read (path)) {
2715 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2720 XMLNodeConstIterator niter;
2722 nlist = node->children();
2726 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2730 if ((prop = (*niter)->property (X_("type"))) == 0) {
2734 DataType type (prop->value());
2736 if ((prop = (*niter)->property (X_("name"))) == 0) {
2740 if (Glib::path_is_absolute (prop->value())) {
2741 /* external file, ignore */
2749 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2750 result.insert (found_path);
2758 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2760 vector<string> state_files;
2762 string this_snapshot_path;
2768 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2769 ripped = ripped.substr (0, ripped.length() - 1);
2772 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2774 if (state_files.empty()) {
2779 this_snapshot_path = _path;
2780 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2781 this_snapshot_path += statefile_suffix;
2783 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2785 if (exclude_this_snapshot && *i == this_snapshot_path) {
2789 if (find_all_sources (*i, result) < 0) {
2797 struct RegionCounter {
2798 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2799 AudioSourceList::iterator iter;
2800 boost::shared_ptr<Region> region;
2803 RegionCounter() : count (0) {}
2807 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2809 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2810 return r.get_value_or (1);
2814 Session::cleanup_regions ()
2816 bool removed = false;
2817 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2819 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2821 uint32_t used = playlists->region_use_count (i->second);
2823 if (used == 0 && !i->second->automatic ()) {
2824 boost::weak_ptr<Region> w = i->second;
2827 RegionFactory::map_remove (w);
2834 // re-check to remove parent references of compound regions
2835 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2836 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2840 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2841 if (0 == playlists->region_use_count (i->second)) {
2842 boost::weak_ptr<Region> w = i->second;
2844 RegionFactory::map_remove (w);
2851 /* dump the history list */
2858 Session::can_cleanup_peakfiles () const
2860 if (deletion_in_progress()) {
2863 if (!_writable || (_state_of_the_state & CannotSave)) {
2864 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2867 if (record_status() == Recording) {
2868 error << _("Cannot cleanup peak-files while recording") << endmsg;
2875 Session::cleanup_peakfiles ()
2877 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2882 assert (can_cleanup_peakfiles ());
2883 assert (!peaks_cleanup_in_progres());
2885 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2887 int timeout = 5000; // 5 seconds
2888 while (!SourceFactory::files_with_peaks.empty()) {
2889 Glib::usleep (1000);
2890 if (--timeout < 0) {
2891 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2892 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2897 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2898 boost::shared_ptr<AudioSource> as;
2899 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2900 as->close_peakfile();
2904 PBD::clear_directory (session_directory().peak_path());
2906 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2908 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2909 boost::shared_ptr<AudioSource> as;
2910 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2911 SourceFactory::setup_peakfile(as, true);
2918 Session::cleanup_sources (CleanupReport& rep)
2920 // FIXME: needs adaptation to midi
2922 vector<boost::shared_ptr<Source> > dead_sources;
2925 vector<string> candidates;
2926 vector<string> unused;
2927 set<string> all_sources;
2936 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2938 /* consider deleting all unused playlists */
2940 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2945 /* sync the "all regions" property of each playlist with its current state
2948 playlists->sync_all_regions_with_regions ();
2950 /* find all un-used sources */
2955 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2957 SourceMap::iterator tmp;
2962 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2966 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2967 dead_sources.push_back (i->second);
2968 i->second->drop_references ();
2974 /* build a list of all the possible audio directories for the session */
2976 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2977 SessionDirectory sdir ((*i).path);
2978 asp += sdir.sound_path();
2980 audio_path += asp.to_string();
2983 /* build a list of all the possible midi directories for the session */
2985 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2986 SessionDirectory sdir ((*i).path);
2987 msp += sdir.midi_path();
2989 midi_path += msp.to_string();
2991 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2992 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2994 /* find all sources, but don't use this snapshot because the
2995 state file on disk still references sources we may have already
2999 find_all_sources_across_snapshots (all_sources, true);
3001 /* add our current source list
3004 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3005 boost::shared_ptr<FileSource> fs;
3006 SourceMap::iterator tmp = i;
3009 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3011 if (!fs->is_stub()) {
3013 if (playlists->source_use_count (fs) != 0) {
3014 all_sources.insert (fs->path());
3017 /* we might not remove this source from disk, because it may be used
3018 by other snapshots, but its not being used in this version
3019 so lets get rid of it now, along with any representative regions
3023 RegionFactory::remove_regions_using_source (i->second);
3025 // also remove source from all_sources
3027 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3028 spath = Glib::path_get_basename (*j);
3029 if (spath == i->second->name()) {
3030 all_sources.erase (j);
3043 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3048 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3050 tmppath1 = canonical_path (spath);
3051 tmppath2 = canonical_path ((*i));
3053 if (tmppath1 == tmppath2) {
3060 unused.push_back (spath);
3064 /* now try to move all unused files into the "dead" directory(ies) */
3066 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3071 /* don't move the file across filesystems, just
3072 stick it in the `dead_dir_name' directory
3073 on whichever filesystem it was already on.
3076 if ((*x).find ("/sounds/") != string::npos) {
3078 /* old school, go up 1 level */
3080 newpath = Glib::path_get_dirname (*x); // "sounds"
3081 newpath = Glib::path_get_dirname (newpath); // "session-name"
3085 /* new school, go up 4 levels */
3087 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3088 newpath = Glib::path_get_dirname (newpath); // "session-name"
3089 newpath = Glib::path_get_dirname (newpath); // "interchange"
3090 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3093 newpath = Glib::build_filename (newpath, dead_dir_name);
3095 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3096 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3100 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3102 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3104 /* the new path already exists, try versioning */
3106 char buf[PATH_MAX+1];
3110 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3113 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3114 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3118 if (version == 999) {
3119 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3123 newpath = newpath_v;
3128 /* it doesn't exist, or we can't read it or something */
3132 g_stat ((*x).c_str(), &statbuf);
3134 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3135 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3136 (*x), newpath, strerror (errno))
3141 /* see if there an easy to find peakfile for this file, and remove it.
3144 string base = Glib::path_get_basename (*x);
3145 base += "%A"; /* this is what we add for the channel suffix of all native files,
3146 or for the first channel of embedded files. it will miss
3147 some peakfiles for other channels
3149 string peakpath = construct_peak_filepath (base);
3151 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3152 if (::g_unlink (peakpath.c_str()) != 0) {
3153 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3154 peakpath, _path, strerror (errno))
3156 /* try to back out */
3157 ::rename (newpath.c_str(), _path.c_str());
3162 rep.paths.push_back (*x);
3163 rep.space += statbuf.st_size;
3166 /* dump the history list */
3170 /* save state so we don't end up a session file
3171 referring to non-existent sources.
3178 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3184 Session::cleanup_trash_sources (CleanupReport& rep)
3186 // FIXME: needs adaptation for MIDI
3188 vector<space_and_path>::iterator i;
3194 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3196 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3198 clear_directory (dead_dir, &rep.space, &rep.paths);
3205 Session::set_dirty ()
3207 /* never mark session dirty during loading */
3209 if (_state_of_the_state & Loading) {
3213 bool was_dirty = dirty();
3215 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3219 DirtyChanged(); /* EMIT SIGNAL */
3225 Session::set_clean ()
3227 bool was_dirty = dirty();
3229 _state_of_the_state = Clean;
3233 DirtyChanged(); /* EMIT SIGNAL */
3238 Session::set_deletion_in_progress ()
3240 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3244 Session::clear_deletion_in_progress ()
3246 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3250 Session::add_controllable (boost::shared_ptr<Controllable> c)
3252 /* this adds a controllable to the list managed by the Session.
3253 this is a subset of those managed by the Controllable class
3254 itself, and represents the only ones whose state will be saved
3255 as part of the session.
3258 Glib::Threads::Mutex::Lock lm (controllables_lock);
3259 controllables.insert (c);
3262 struct null_deleter { void operator()(void const *) const {} };
3265 Session::remove_controllable (Controllable* c)
3267 if (_state_of_the_state & Deletion) {
3271 Glib::Threads::Mutex::Lock lm (controllables_lock);
3273 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3275 if (x != controllables.end()) {
3276 controllables.erase (x);
3280 boost::shared_ptr<Controllable>
3281 Session::controllable_by_id (const PBD::ID& id)
3283 Glib::Threads::Mutex::Lock lm (controllables_lock);
3285 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3286 if ((*i)->id() == id) {
3291 return boost::shared_ptr<Controllable>();
3294 boost::shared_ptr<Controllable>
3295 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3297 boost::shared_ptr<Controllable> c;
3298 boost::shared_ptr<Route> r;
3300 switch (desc.top_level_type()) {
3301 case ControllableDescriptor::NamedRoute:
3303 std::string str = desc.top_level_name();
3304 if (str == "Master" || str == "master") {
3306 } else if (str == "control" || str == "listen") {
3309 r = route_by_name (desc.top_level_name());
3314 case ControllableDescriptor::RemoteControlID:
3315 r = route_by_remote_id (desc.rid());
3323 switch (desc.subtype()) {
3324 case ControllableDescriptor::Gain:
3325 c = r->gain_control ();
3328 case ControllableDescriptor::Trim:
3329 c = r->trim()->gain_control ();
3332 case ControllableDescriptor::Solo:
3333 c = r->solo_control();
3336 case ControllableDescriptor::Mute:
3337 c = r->mute_control();
3340 case ControllableDescriptor::Recenable:
3342 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3345 c = t->rec_enable_control ();
3350 case ControllableDescriptor::PanDirection:
3352 c = r->pannable()->pan_azimuth_control;
3356 case ControllableDescriptor::PanWidth:
3358 c = r->pannable()->pan_width_control;
3362 case ControllableDescriptor::PanElevation:
3364 c = r->pannable()->pan_elevation_control;
3368 case ControllableDescriptor::Balance:
3369 /* XXX simple pan control */
3372 case ControllableDescriptor::PluginParameter:
3374 uint32_t plugin = desc.target (0);
3375 uint32_t parameter_index = desc.target (1);
3377 /* revert to zero based counting */
3383 if (parameter_index > 0) {
3387 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3390 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3391 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3396 case ControllableDescriptor::SendGain:
3398 uint32_t send = desc.target (0);
3400 /* revert to zero-based counting */
3406 boost::shared_ptr<Processor> p = r->nth_send (send);
3409 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3410 boost::shared_ptr<Amp> a = s->amp();
3413 c = s->amp()->gain_control();
3420 /* relax and return a null pointer */
3428 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3431 Stateful::add_instant_xml (node, _path);
3434 if (write_to_config) {
3435 Config->add_instant_xml (node);
3440 Session::instant_xml (const string& node_name)
3442 return Stateful::instant_xml (node_name, _path);
3446 Session::save_history (string snapshot_name)
3454 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3455 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3459 if (snapshot_name.empty()) {
3460 snapshot_name = _current_snapshot_name;
3463 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3464 const string backup_filename = history_filename + backup_suffix;
3465 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3466 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3468 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3469 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3470 error << _("could not backup old history file, current history not saved") << endmsg;
3475 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3477 if (!tree.write (xml_path))
3479 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3481 if (g_remove (xml_path.c_str()) != 0) {
3482 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3483 xml_path, g_strerror (errno)) << endmsg;
3485 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3486 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3487 backup_path, g_strerror (errno)) << endmsg;
3497 Session::restore_history (string snapshot_name)
3501 if (snapshot_name.empty()) {
3502 snapshot_name = _current_snapshot_name;
3505 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3506 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3508 info << "Loading history from " << xml_path << endmsg;
3510 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3511 info << string_compose (_("%1: no history file \"%2\" for this session."),
3512 _name, xml_path) << endmsg;
3516 if (!tree.read (xml_path)) {
3517 error << string_compose (_("Could not understand session history file \"%1\""),
3518 xml_path) << endmsg;
3525 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3528 UndoTransaction* ut = new UndoTransaction ();
3531 ut->set_name(t->property("name")->value());
3532 stringstream ss(t->property("tv-sec")->value());
3534 ss.str(t->property("tv-usec")->value());
3536 ut->set_timestamp(tv);
3538 for (XMLNodeConstIterator child_it = t->children().begin();
3539 child_it != t->children().end(); child_it++)
3541 XMLNode *n = *child_it;
3544 if (n->name() == "MementoCommand" ||
3545 n->name() == "MementoUndoCommand" ||
3546 n->name() == "MementoRedoCommand") {
3548 if ((c = memento_command_factory(n))) {
3552 } else if (n->name() == "NoteDiffCommand") {
3553 PBD::ID id (n->property("midi-source")->value());
3554 boost::shared_ptr<MidiSource> midi_source =
3555 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3557 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3559 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3562 } else if (n->name() == "SysExDiffCommand") {
3564 PBD::ID id (n->property("midi-source")->value());
3565 boost::shared_ptr<MidiSource> midi_source =
3566 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3568 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3570 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3573 } else if (n->name() == "PatchChangeDiffCommand") {
3575 PBD::ID id (n->property("midi-source")->value());
3576 boost::shared_ptr<MidiSource> midi_source =
3577 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3579 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3581 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3584 } else if (n->name() == "StatefulDiffCommand") {
3585 if ((c = stateful_diff_command_factory (n))) {
3586 ut->add_command (c);
3589 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3600 Session::config_changed (std::string p, bool ours)
3606 if (p == "seamless-loop") {
3608 } else if (p == "rf-speed") {
3610 } else if (p == "auto-loop") {
3612 } else if (p == "auto-input") {
3614 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3615 /* auto-input only makes a difference if we're rolling */
3616 set_track_monitor_input_status (!config.get_auto_input());
3619 } else if (p == "punch-in") {
3623 if ((location = _locations->auto_punch_location()) != 0) {
3625 if (config.get_punch_in ()) {
3626 replace_event (SessionEvent::PunchIn, location->start());
3628 remove_event (location->start(), SessionEvent::PunchIn);
3632 } else if (p == "punch-out") {
3636 if ((location = _locations->auto_punch_location()) != 0) {
3638 if (config.get_punch_out()) {
3639 replace_event (SessionEvent::PunchOut, location->end());
3641 clear_events (SessionEvent::PunchOut);
3645 } else if (p == "edit-mode") {
3647 Glib::Threads::Mutex::Lock lm (playlists->lock);
3649 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3650 (*i)->set_edit_mode (Config->get_edit_mode ());
3653 } else if (p == "use-video-sync") {
3655 waiting_for_sync_offset = config.get_use_video_sync();
3657 } else if (p == "mmc-control") {
3659 //poke_midi_thread ();
3661 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3663 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3665 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3667 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3669 } else if (p == "midi-control") {
3671 //poke_midi_thread ();
3673 } else if (p == "raid-path") {
3675 setup_raid_path (config.get_raid_path());
3677 } else if (p == "timecode-format") {
3681 } else if (p == "video-pullup") {
3685 } else if (p == "seamless-loop") {
3687 if (play_loop && transport_rolling()) {
3688 // to reset diskstreams etc
3689 request_play_loop (true);
3692 } else if (p == "rf-speed") {
3694 cumulative_rf_motion = 0;
3697 } else if (p == "click-sound") {
3699 setup_click_sounds (1);
3701 } else if (p == "click-emphasis-sound") {
3703 setup_click_sounds (-1);
3705 } else if (p == "clicking") {
3707 if (Config->get_clicking()) {
3708 if (_click_io && click_data) { // don't require emphasis data
3715 } else if (p == "click-gain") {
3718 _click_gain->set_gain (Config->get_click_gain(), this);
3721 } else if (p == "send-mtc") {
3723 if (Config->get_send_mtc ()) {
3724 /* mark us ready to send */
3725 next_quarter_frame_to_send = 0;
3728 } else if (p == "send-mmc") {
3730 _mmc->enable_send (Config->get_send_mmc ());
3732 } else if (p == "midi-feedback") {
3734 session_midi_feedback = Config->get_midi_feedback();
3736 } else if (p == "jack-time-master") {
3738 engine().reset_timebase ();
3740 } else if (p == "native-file-header-format") {
3742 if (!first_file_header_format_reset) {
3743 reset_native_file_format ();
3746 first_file_header_format_reset = false;
3748 } else if (p == "native-file-data-format") {
3750 if (!first_file_data_format_reset) {
3751 reset_native_file_format ();
3754 first_file_data_format_reset = false;
3756 } else if (p == "external-sync") {
3757 if (!config.get_external_sync()) {
3758 drop_sync_source ();
3760 switch_to_sync_source (Config->get_sync_source());
3762 } else if (p == "denormal-model") {
3764 } else if (p == "history-depth") {
3765 set_history_depth (Config->get_history_depth());
3766 } else if (p == "remote-model") {
3767 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3770 } else if (p == "initial-program-change") {
3772 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3775 buf[0] = MIDI::program; // channel zero by default
3776 buf[1] = (Config->get_initial_program_change() & 0x7f);
3778 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3780 } else if (p == "solo-mute-override") {
3781 // catch_up_on_solo_mute_override ();
3782 } else if (p == "listen-position" || p == "pfl-position") {
3783 listen_position_changed ();
3784 } else if (p == "solo-control-is-listen-control") {
3785 solo_control_mode_changed ();
3786 } else if (p == "solo-mute-gain") {
3787 _solo_cut_control->Changed();
3788 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3789 last_timecode_valid = false;
3790 } else if (p == "playback-buffer-seconds") {
3791 AudioSource::allocate_working_buffers (frame_rate());
3792 } else if (p == "ltc-source-port") {
3793 reconnect_ltc_input ();
3794 } else if (p == "ltc-sink-port") {
3795 reconnect_ltc_output ();
3796 } else if (p == "timecode-generator-offset") {
3797 ltc_tx_parse_offset();
3798 } else if (p == "auto-return-target-list") {
3799 follow_playhead_priority ();
3806 Session::set_history_depth (uint32_t d)
3808 _history.set_depth (d);
3812 Session::load_diskstreams_2X (XMLNode const & node, int)
3815 XMLNodeConstIterator citer;
3817 clist = node.children();
3819 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3822 /* diskstreams added automatically by DiskstreamCreated handler */
3823 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3824 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3825 _diskstreams_2X.push_back (dsp);
3827 error << _("Session: unknown diskstream type in XML") << endmsg;
3831 catch (failed_constructor& err) {
3832 error << _("Session: could not load diskstream via XML state") << endmsg;
3840 /** Connect things to the MMC object */
3842 Session::setup_midi_machine_control ()
3844 _mmc = new MIDI::MachineControl;
3845 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3847 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3848 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3849 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3850 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3851 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3852 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3853 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3854 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3855 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3856 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3857 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3858 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3859 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3861 /* also handle MIDI SPP because its so common */
3863 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3864 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3865 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3868 boost::shared_ptr<Controllable>
3869 Session::solo_cut_control() const
3871 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3872 controls in Ardour that currently get presented to the user in the GUI that require
3873 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3875 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3876 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3880 return _solo_cut_control;
3884 Session::rename (const std::string& new_name)
3886 string legal_name = legalize_for_path (new_name);
3892 string const old_sources_root = _session_dir->sources_root();
3894 if (!_writable || (_state_of_the_state & CannotSave)) {
3895 error << _("Cannot rename read-only session.") << endmsg;
3896 return 0; // don't show "messed up" warning
3898 if (record_status() == Recording) {
3899 error << _("Cannot rename session while recording") << endmsg;
3900 return 0; // don't show "messed up" warning
3903 StateProtector stp (this);
3908 * interchange subdirectory
3912 * Backup files are left unchanged and not renamed.
3915 /* Windows requires that we close all files before attempting the
3916 * rename. This works on other platforms, but isn't necessary there.
3917 * Leave it in place for all platforms though, since it may help
3918 * catch issues that could arise if the way Source files work ever
3919 * change (since most developers are not using Windows).
3922 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3923 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3929 /* pass one: not 100% safe check that the new directory names don't
3933 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3937 /* this is a stupid hack because Glib::path_get_dirname() is
3938 * lexical-only, and so passing it /a/b/c/ gives a different
3939 * result than passing it /a/b/c ...
3942 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3943 oldstr = oldstr.substr (0, oldstr.length() - 1);
3946 string base = Glib::path_get_dirname (oldstr);
3948 newstr = Glib::build_filename (base, legal_name);
3950 cerr << "Looking for " << newstr << endl;
3952 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3953 cerr << " exists\n";
3962 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3968 /* this is a stupid hack because Glib::path_get_dirname() is
3969 * lexical-only, and so passing it /a/b/c/ gives a different
3970 * result than passing it /a/b/c ...
3973 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3974 oldstr = oldstr.substr (0, oldstr.length() - 1);
3977 string base = Glib::path_get_dirname (oldstr);
3978 newstr = Glib::build_filename (base, legal_name);
3980 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3982 cerr << "Rename " << oldstr << " => " << newstr << endl;
3983 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3984 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3985 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3989 /* Reset path in "session dirs" */
3994 /* reset primary SessionDirectory object */
3997 (*_session_dir) = newstr;
4002 /* now rename directory below session_dir/interchange */
4004 string old_interchange_dir;
4005 string new_interchange_dir;
4007 /* use newstr here because we renamed the path
4008 * (folder/directory) that used to be oldstr to newstr above
4011 v.push_back (newstr);
4012 v.push_back (interchange_dir_name);
4013 v.push_back (Glib::path_get_basename (oldstr));
4015 old_interchange_dir = Glib::build_filename (v);
4018 v.push_back (newstr);
4019 v.push_back (interchange_dir_name);
4020 v.push_back (legal_name);
4022 new_interchange_dir = Glib::build_filename (v);
4024 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4026 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4027 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4028 old_interchange_dir, new_interchange_dir,
4031 error << string_compose (_("renaming %s as %2 failed (%3)"),
4032 old_interchange_dir, new_interchange_dir,
4041 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4042 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4044 cerr << "Rename " << oldstr << " => " << newstr << endl;
4046 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4047 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4048 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4054 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4056 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4057 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4059 cerr << "Rename " << oldstr << " => " << newstr << endl;
4061 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4062 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4063 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4068 /* remove old name from recent sessions */
4069 remove_recent_sessions (_path);
4072 /* update file source paths */
4074 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4075 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4077 string p = fs->path ();
4078 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4080 SourceFactory::setup_peakfile(i->second, true);
4084 _current_snapshot_name = new_name;
4089 /* save state again to get everything just right */
4091 save_state (_current_snapshot_name);
4093 /* add to recent sessions */
4095 store_recent_sessions (new_name, _path);
4101 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4103 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4107 if (!tree.read (xmlpath)) {
4115 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4118 bool found_sr = false;
4119 bool found_data_format = false;
4121 if (get_session_info_from_path (tree, xmlpath)) {
4127 const XMLProperty* prop;
4128 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
4129 sample_rate = atoi (prop->value());
4133 const XMLNodeList& children (tree.root()->children());
4134 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4135 const XMLNode* child = *c;
4136 if (child->name() == "Config") {
4137 const XMLNodeList& options (child->children());
4138 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4139 const XMLNode* option = *oc;
4140 const XMLProperty* name = option->property("name");
4146 if (name->value() == "native-file-data-format") {
4147 const XMLProperty* value = option->property ("value");
4149 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4151 found_data_format = true;
4157 if (found_data_format) {
4162 return !(found_sr && found_data_format); // zero if they are both found
4165 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4166 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4169 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4173 SourcePathMap source_path_map;
4175 boost::shared_ptr<AudioFileSource> afs;
4180 Glib::Threads::Mutex::Lock lm (source_lock);
4182 cerr << " total sources = " << sources.size();
4184 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4185 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4191 if (fs->within_session()) {
4195 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4196 source_path_map[fs->path()].push_back (fs);
4198 SeveralFileSources v;
4200 source_path_map.insert (make_pair (fs->path(), v));
4206 cerr << " fsources = " << total << endl;
4208 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4210 /* tell caller where we are */
4212 string old_path = i->first;
4214 callback (n, total, old_path);
4216 cerr << old_path << endl;
4220 switch (i->second.front()->type()) {
4221 case DataType::AUDIO:
4222 new_path = new_audio_source_path_for_embedded (old_path);
4225 case DataType::MIDI:
4226 /* XXX not implemented yet */
4230 if (new_path.empty()) {
4234 cerr << "Move " << old_path << " => " << new_path << endl;
4236 if (!copy_file (old_path, new_path)) {
4237 cerr << "failed !\n";
4241 /* make sure we stop looking in the external
4242 dir/folder. Remember, this is an all-or-nothing
4243 operations, it doesn't merge just some files.
4245 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4247 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4248 (*f)->set_path (new_path);
4253 save_state ("", false, false);
4259 bool accept_all_files (string const &, void *)
4265 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4267 /* 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.
4272 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4274 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4276 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4278 v.push_back (new_session_folder); /* full path */
4279 v.push_back (interchange_dir_name);
4280 v.push_back (new_session_path); /* just one directory/folder */
4281 v.push_back (typedir);
4282 v.push_back (Glib::path_get_basename (old_path));
4284 return Glib::build_filename (v);
4288 Session::save_as (SaveAs& saveas)
4290 vector<string> files;
4291 string current_folder = Glib::path_get_dirname (_path);
4292 string new_folder = legalize_for_path (saveas.new_name);
4293 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4294 int64_t total_bytes = 0;
4298 int32_t internal_file_cnt = 0;
4300 vector<string> do_not_copy_extensions;
4301 do_not_copy_extensions.push_back (statefile_suffix);
4302 do_not_copy_extensions.push_back (pending_suffix);
4303 do_not_copy_extensions.push_back (backup_suffix);
4304 do_not_copy_extensions.push_back (temp_suffix);
4305 do_not_copy_extensions.push_back (history_suffix);
4307 /* get total size */
4309 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4311 /* need to clear this because
4312 * find_files_matching_filter() is cumulative
4317 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4319 all += files.size();
4321 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4323 g_stat ((*i).c_str(), &gsb);
4324 total_bytes += gsb.st_size;
4328 /* save old values so we can switch back if we are not switching to the new session */
4330 string old_path = _path;
4331 string old_name = _name;
4332 string old_snapshot = _current_snapshot_name;
4333 string old_sd = _session_dir->root_path();
4334 vector<string> old_search_path[DataType::num_types];
4335 string old_config_search_path[DataType::num_types];
4337 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4338 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4339 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4340 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4342 /* switch session directory */
4344 (*_session_dir) = to_dir;
4346 /* create new tree */
4348 if (!_session_dir->create()) {
4349 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4354 /* copy all relevant files. Find each location in session_dirs,
4355 * and copy files from there to target.
4358 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4360 /* need to clear this because
4361 * find_files_matching_filter() is cumulative
4366 const size_t prefix_len = (*sd).path.size();
4368 /* Work just on the files within this session dir */
4370 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4372 /* add dir separator to protect against collisions with
4373 * track names (e.g. track named "audiofiles" or
4377 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4378 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4379 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4381 /* copy all the files. Handling is different for media files
4382 than others because of the *silly* subtree we have below the interchange
4383 folder. That really was a bad idea, but I'm not fixing it as part of
4384 implementing ::save_as().
4387 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4389 std::string from = *i;
4392 string filename = Glib::path_get_basename (from);
4393 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4394 if (filename == ".DS_STORE") {
4399 if (from.find (audiofile_dir_string) != string::npos) {
4401 /* audio file: only copy if asked */
4403 if (saveas.include_media && saveas.copy_media) {
4405 string to = make_new_media_path (*i, to_dir, new_folder);
4407 info << "media file copying from " << from << " to " << to << endmsg;
4409 if (!copy_file (from, to)) {
4410 throw Glib::FileError (Glib::FileError::IO_ERROR,
4411 string_compose(_("\ncopying \"%1\" failed !"), from));
4415 /* we found media files inside the session folder */
4417 internal_file_cnt++;
4419 } else if (from.find (midifile_dir_string) != string::npos) {
4421 /* midi file: always copy unless
4422 * creating an empty new session
4425 if (saveas.include_media) {
4427 string to = make_new_media_path (*i, to_dir, new_folder);
4429 info << "media file copying from " << from << " to " << to << endmsg;
4431 if (!copy_file (from, to)) {
4432 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4436 /* we found media files inside the session folder */
4438 internal_file_cnt++;
4440 } else if (from.find (analysis_dir_string) != string::npos) {
4442 /* make sure analysis dir exists in
4443 * new session folder, but we're not
4444 * copying analysis files here, see
4448 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4453 /* normal non-media file. Don't copy state, history, etc.
4456 bool do_copy = true;
4458 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4459 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4460 /* end of filename matches extension, do not copy file */
4466 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4467 /* don't copy peakfiles if
4468 * we're not copying media
4474 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4476 info << "attempting to make directory/folder " << to << endmsg;
4478 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4479 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4482 info << "attempting to copy " << from << " to " << to << endmsg;
4484 if (!copy_file (from, to)) {
4485 throw Glib::FileError (Glib::FileError::IO_ERROR,
4486 string_compose(_("\ncopying \"%1\" failed !"), from));
4491 /* measure file size even if we're not going to copy so that our Progress
4492 signals are correct, since we included these do-not-copy files
4493 in the computation of the total size and file count.
4497 g_stat (from.c_str(), &gsb);
4498 copied += gsb.st_size;
4501 double fraction = (double) copied / total_bytes;
4503 bool keep_going = true;
4505 if (saveas.copy_media) {
4507 /* no need or expectation of this if
4508 * media is not being copied, because
4509 * it will be fast(ish).
4512 /* tell someone "X percent, file M of N"; M is one-based */
4514 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4522 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4528 /* copy optional folders, if any */
4530 string old = plugins_dir ();
4531 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4532 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4533 copy_files (old, newdir);
4536 old = externals_dir ();
4537 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4538 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4539 copy_files (old, newdir);
4542 old = automation_dir ();
4543 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4544 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4545 copy_files (old, newdir);
4548 if (saveas.include_media) {
4550 if (saveas.copy_media) {
4551 #ifndef PLATFORM_WINDOWS
4552 /* There are problems with analysis files on
4553 * Windows, because they used a colon in their
4554 * names as late as 4.0. Colons are not legal
4555 * under Windows even if NTFS allows them.
4557 * This is a tricky problem to solve so for
4558 * just don't copy these files. They will be
4559 * regenerated as-needed anyway, subject to the
4560 * existing issue that the filenames will be
4561 * rejected by Windows, which is a separate
4562 * problem (though related).
4565 /* only needed if we are copying media, since the
4566 * analysis data refers to media data
4569 old = analysis_dir ();
4570 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4571 string newdir = Glib::build_filename (to_dir, "analysis");
4572 copy_files (old, newdir);
4574 #endif /* PLATFORM_WINDOWS */
4580 _current_snapshot_name = saveas.new_name;
4581 _name = saveas.new_name;
4583 if (saveas.include_media && !saveas.copy_media) {
4585 /* reset search paths of the new session (which we're pretending to be right now) to
4586 include the original session search path, so we can still find all audio.
4589 if (internal_file_cnt) {
4590 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4591 ensure_search_path_includes (*s, DataType::AUDIO);
4592 cerr << "be sure to include " << *s << " for audio" << endl;
4595 /* we do not do this for MIDI because we copy
4596 all MIDI files if saveas.include_media is
4602 bool was_dirty = dirty ();
4604 save_state ("", false, false, !saveas.include_media);
4605 save_default_options ();
4607 if (saveas.copy_media && saveas.copy_external) {
4608 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4609 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4613 saveas.final_session_folder_name = _path;
4615 store_recent_sessions (_name, _path);
4617 if (!saveas.switch_to) {
4619 /* switch back to the way things were */
4623 _current_snapshot_name = old_snapshot;
4625 (*_session_dir) = old_sd;
4631 if (internal_file_cnt) {
4632 /* reset these to their original values */
4633 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4634 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4639 /* prune session dirs, and update disk space statistics
4644 session_dirs.clear ();
4645 session_dirs.push_back (sp);
4646 refresh_disk_space ();
4648 /* ensure that all existing tracks reset their current capture source paths
4650 reset_write_sources (true, true);
4652 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4653 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4656 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4657 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4663 if (fs->within_session()) {
4664 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4665 fs->set_path (newpath);
4670 } catch (Glib::FileError& e) {
4672 saveas.failure_message = e.what();
4674 /* recursively remove all the directories */
4676 remove_directory (to_dir);
4684 saveas.failure_message = _("unknown reason");
4686 /* recursively remove all the directories */
4688 remove_directory (to_dir);