2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
31 #include <cstdio> /* snprintf(3) ... grrr */
44 #include <sys/param.h>
45 #include <sys/mount.h>
48 #ifdef HAVE_SYS_STATVFS_H
49 #include <sys/statvfs.h>
53 #include <pbd/gstdio_compat.h>
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/boost_debug.h"
67 #include "pbd/basename.h"
68 #include "pbd/controllable_descriptor.h"
69 #include "pbd/debug.h"
70 #include "pbd/enumwriter.h"
71 #include "pbd/error.h"
72 #include "pbd/file_utils.h"
73 #include "pbd/pathexpand.h"
74 #include "pbd/pthread_utils.h"
75 #include "pbd/stacktrace.h"
76 #include "pbd/convert.h"
77 #include "pbd/localtime_r.h"
79 #include "ardour/amp.h"
80 #include "ardour/async_midi_port.h"
81 #include "ardour/audio_diskstream.h"
82 #include "ardour/audio_track.h"
83 #include "ardour/audioengine.h"
84 #include "ardour/audiofilesource.h"
85 #include "ardour/audioregion.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/butler.h"
88 #include "ardour/control_protocol_manager.h"
89 #include "ardour/directory_names.h"
90 #include "ardour/filename_extensions.h"
91 #include "ardour/graph.h"
92 #include "ardour/location.h"
93 #include "ardour/midi_model.h"
94 #include "ardour/midi_patch_manager.h"
95 #include "ardour/midi_region.h"
96 #include "ardour/midi_scene_changer.h"
97 #include "ardour/midi_source.h"
98 #include "ardour/midi_track.h"
99 #include "ardour/pannable.h"
100 #include "ardour/playlist_factory.h"
101 #include "ardour/playlist_source.h"
102 #include "ardour/port.h"
103 #include "ardour/processor.h"
104 #include "ardour/profile.h"
105 #include "ardour/proxy_controllable.h"
106 #include "ardour/recent_sessions.h"
107 #include "ardour/region_factory.h"
108 #include "ardour/route_group.h"
109 #include "ardour/send.h"
110 #include "ardour/session.h"
111 #include "ardour/session_directory.h"
112 #include "ardour/session_metadata.h"
113 #include "ardour/session_playlists.h"
114 #include "ardour/session_state_utils.h"
115 #include "ardour/silentfilesource.h"
116 #include "ardour/sndfilesource.h"
117 #include "ardour/source_factory.h"
118 #include "ardour/speakers.h"
119 #include "ardour/template_utils.h"
120 #include "ardour/tempo.h"
121 #include "ardour/ticker.h"
122 #include "ardour/user_bundle.h"
124 #include "control_protocol/control_protocol.h"
130 using namespace ARDOUR;
133 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
136 Session::pre_engine_init (string fullpath)
138 if (fullpath.empty()) {
140 throw failed_constructor();
143 /* discover canonical fullpath */
145 _path = canonical_path(fullpath);
148 if (Profile->get_trx() ) {
149 // Waves TracksLive has a usecase of session replacement with a new one.
150 // We should check session state file (<session_name>.ardour) existance
151 // to determine if the session is new or not
153 string full_session_name = Glib::build_filename( fullpath, _name );
154 full_session_name += statefile_suffix;
156 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
158 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
161 /* finish initialization that can't be done in a normal C++ constructor
165 timerclear (&last_mmc_step);
166 g_atomic_int_set (&processing_prohibited, 0);
167 g_atomic_int_set (&_record_status, Disabled);
168 g_atomic_int_set (&_playback_load, 100);
169 g_atomic_int_set (&_capture_load, 100);
171 _all_route_group->set_active (true, this);
172 interpolation.add_channel_to (0, 0);
174 if (config.get_use_video_sync()) {
175 waiting_for_sync_offset = true;
177 waiting_for_sync_offset = false;
180 last_rr_session_dir = session_dirs.begin();
182 set_history_depth (Config->get_history_depth());
184 /* default: assume simple stereo speaker configuration */
186 _speakers->setup_default_speakers (2);
188 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
189 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
190 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
191 add_controllable (_solo_cut_control);
193 /* These are all static "per-class" signals */
195 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
196 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
197 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
198 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
199 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
201 /* stop IO objects from doing stuff until we're ready for them */
203 Delivery::disable_panners ();
204 IO::disable_connecting ();
208 Session::post_engine_init ()
210 BootMessage (_("Set block size and sample rate"));
212 set_block_size (_engine.samples_per_cycle());
213 set_frame_rate (_engine.sample_rate());
215 BootMessage (_("Using configuration"));
217 _midi_ports = new MidiPortManager;
219 MIDISceneChanger* msc;
221 _scene_changer = msc = new MIDISceneChanger (*this);
222 msc->set_input_port (scene_input_port());
223 msc->set_output_port (scene_out());
225 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
226 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
228 setup_midi_machine_control ();
230 if (_butler->start_thread()) {
234 if (start_midi_thread ()) {
238 setup_click_sounds (0);
239 setup_midi_control ();
241 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
242 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
245 /* tempo map requires sample rate knowledge */
248 _tempo_map = new TempoMap (_current_frame_rate);
249 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
251 /* MidiClock requires a tempo map */
253 midi_clock = new MidiClockTicker ();
254 midi_clock->set_session (this);
256 /* crossfades require sample rate knowledge */
258 SndFileSource::setup_standard_crossfades (*this, frame_rate());
259 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
261 AudioDiskstream::allocate_working_buffers();
262 refresh_disk_space ();
264 /* we're finally ready to call set_state() ... all objects have
265 * been created, the engine is running.
269 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
273 // set_state() will call setup_raid_path(), but if it's a new session we need
274 // to call setup_raid_path() here.
275 setup_raid_path (_path);
280 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
281 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
283 Config->map_parameters (ff);
284 config.map_parameters (ft);
285 _butler->map_parameters ();
287 /* Reset all panners */
289 Delivery::reset_panners ();
291 /* this will cause the CPM to instantiate any protocols that are in use
292 * (or mandatory), which will pass it this Session, and then call
293 * set_state() on each instantiated protocol to match stored state.
296 ControlProtocolManager::instance().set_session (this);
298 /* This must be done after the ControlProtocolManager set_session above,
299 as it will set states for ports which the ControlProtocolManager creates.
302 // XXX set state of MIDI::Port's
303 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
305 /* And this must be done after the MIDI::Manager::set_port_states as
306 * it will try to make connections whose details are loaded by set_port_states.
311 /* Let control protocols know that we are now all connected, so they
312 * could start talking to surfaces if they want to.
315 ControlProtocolManager::instance().midi_connectivity_established ();
317 if (_is_new && !no_auto_connect()) {
318 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
319 auto_connect_master_bus ();
322 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
324 /* update latencies */
326 initialize_latencies ();
328 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
329 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
330 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
332 } catch (AudioEngine::PortRegistrationFailure& err) {
333 /* handle this one in a different way than all others, so that its clear what happened */
334 error << err.what() << endmsg;
340 BootMessage (_("Reset Remote Controls"));
342 // send_full_time_code (0);
343 _engine.transport_locate (0);
345 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
346 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
348 MIDI::Name::MidiPatchManager::instance().set_session (this);
351 /* initial program change will be delivered later; see ::config_changed() */
353 _state_of_the_state = Clean;
355 Port::set_connecting_blocked (false);
357 DirtyChanged (); /* EMIT SIGNAL */
361 } else if (state_was_pending) {
363 remove_pending_capture_state ();
364 state_was_pending = false;
367 /* Now, finally, we can fill the playback buffers */
369 BootMessage (_("Filling playback buffers"));
371 boost::shared_ptr<RouteList> rl = routes.reader();
372 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
373 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
374 if (trk && !trk->hidden()) {
375 trk->seek (_transport_frame, true);
383 Session::session_loaded ()
387 _state_of_the_state = Clean;
389 DirtyChanged (); /* EMIT SIGNAL */
393 } else if (state_was_pending) {
395 remove_pending_capture_state ();
396 state_was_pending = false;
399 /* Now, finally, we can fill the playback buffers */
401 BootMessage (_("Filling playback buffers"));
402 force_locate (_transport_frame, false);
406 Session::raid_path () const
408 Searchpath raid_search_path;
410 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
411 raid_search_path += (*i).path;
414 return raid_search_path.to_string ();
418 Session::setup_raid_path (string path)
427 session_dirs.clear ();
429 Searchpath search_path(path);
430 Searchpath sound_search_path;
431 Searchpath midi_search_path;
433 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
435 sp.blocks = 0; // not needed
436 session_dirs.push_back (sp);
438 SessionDirectory sdir(sp.path);
440 sound_search_path += sdir.sound_path ();
441 midi_search_path += sdir.midi_path ();
444 // reset the round-robin soundfile path thingie
445 last_rr_session_dir = session_dirs.begin();
449 Session::path_is_within_session (const std::string& path)
451 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
452 if (PBD::path_is_within (i->path, path)) {
460 Session::ensure_subdirs ()
464 dir = session_directory().peak_path();
466 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
467 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
471 dir = session_directory().sound_path();
473 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
474 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
478 dir = session_directory().midi_path();
480 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
481 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
485 dir = session_directory().dead_path();
487 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
488 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
492 dir = session_directory().export_path();
494 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
495 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
499 dir = analysis_dir ();
501 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
502 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 dir = plugins_dir ();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = externals_dir ();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
523 /** @param session_template directory containing session template, or empty.
524 * Caller must not hold process lock.
527 Session::create (const string& session_template, BusProfile* bus_profile)
529 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
534 if (ensure_subdirs ()) {
538 _writable = exists_and_writable (_path);
540 if (!session_template.empty()) {
541 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
543 FILE* in = g_fopen (in_path.c_str(), "rb");
546 /* no need to call legalize_for_path() since the string
547 * in session_template is already a legal path name
549 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
551 FILE* out = g_fopen (out_path.c_str(), "wb");
555 stringstream new_session;
558 size_t charsRead = fread (buf, sizeof(char), 1024, in);
561 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
566 if (charsRead == 0) {
569 new_session.write (buf, charsRead);
573 string file_contents = new_session.str();
574 size_t writeSize = file_contents.length();
575 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
576 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
584 if (!ARDOUR::Profile->get_trx()) {
585 /* Copy plugin state files from template to new session */
586 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
587 copy_recurse (template_plugins, plugins_dir ());
593 error << string_compose (_("Could not open %1 for writing session template"), out_path)
600 error << string_compose (_("Could not open session template %1 for reading"), in_path)
607 if (Profile->get_trx()) {
609 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
610 Remember that this is a brand new session. Sessions
611 loaded from saved state will get this range from the saved state.
614 set_session_range_location (0, 0);
616 /* Initial loop location, from absolute zero, length 10 seconds */
618 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
619 _locations->add (loc, true);
620 set_auto_loop_location (loc);
623 _state_of_the_state = Clean;
625 /* set up Master Out and Control Out if necessary */
630 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
632 // Waves Tracks: always create master bus for Tracks
633 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
634 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
638 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
639 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
642 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
643 r->input()->ensure_io (count, false, this);
644 r->output()->ensure_io (count, false, this);
650 /* prohibit auto-connect to master, because there isn't one */
651 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
655 add_routes (rl, false, false, false);
658 // Waves Tracks: Skip this. Always use autoconnection for Tracks
659 if (!ARDOUR::Profile->get_trx()) {
661 /* this allows the user to override settings with an environment variable.
664 if (no_auto_connect()) {
665 bus_profile->input_ac = AutoConnectOption (0);
666 bus_profile->output_ac = AutoConnectOption (0);
669 Config->set_input_auto_connect (bus_profile->input_ac);
670 Config->set_output_auto_connect (bus_profile->output_ac);
674 if (Config->get_use_monitor_bus() && bus_profile) {
675 add_monitor_section ();
682 Session::maybe_write_autosave()
684 if (dirty() && record_status() != Recording) {
685 save_state("", true);
690 Session::remove_pending_capture_state ()
692 std::string pending_state_file_path(_session_dir->root_path());
694 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
696 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
698 if (g_remove (pending_state_file_path.c_str()) != 0) {
699 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
700 pending_state_file_path, g_strerror (errno)) << endmsg;
704 /** Rename a state file.
705 * @param old_name Old snapshot name.
706 * @param new_name New snapshot name.
709 Session::rename_state (string old_name, string new_name)
711 if (old_name == _current_snapshot_name || old_name == _name) {
712 /* refuse to rename the current snapshot or the "main" one */
716 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
717 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
719 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
720 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
722 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
723 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
724 old_name, new_name, g_strerror(errno)) << endmsg;
728 /** Remove a state file.
729 * @param snapshot_name Snapshot name.
732 Session::remove_state (string snapshot_name)
734 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
735 // refuse to remove the current snapshot or the "main" one
739 std::string xml_path(_session_dir->root_path());
741 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
743 if (!create_backup_file (xml_path)) {
744 // don't remove it if a backup can't be made
745 // create_backup_file will log the error.
750 if (g_remove (xml_path.c_str()) != 0) {
751 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
752 xml_path, g_strerror (errno)) << endmsg;
756 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
758 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
761 std::string xml_path(_session_dir->root_path());
763 /* prevent concurrent saves from different threads */
765 Glib::Threads::Mutex::Lock lm (save_state_lock);
767 if (!_writable || (_state_of_the_state & CannotSave)) {
771 if (g_atomic_int_get(&_suspend_save)) {
775 _save_queued = false;
777 if (!_engine.connected ()) {
778 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
784 /* tell sources we're saving first, in case they write out to a new file
785 * which should be saved with the state rather than the old one */
786 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
788 i->second->session_saved();
789 } catch (Evoral::SMF::FileError& e) {
790 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
794 SessionSaveUnderway (); /* EMIT SIGNAL */
797 tree.set_root (&get_template());
799 tree.set_root (&get_state());
802 if (snapshot_name.empty()) {
803 snapshot_name = _current_snapshot_name;
804 } else if (switch_to_snapshot) {
805 _current_snapshot_name = snapshot_name;
810 /* proper save: use statefile_suffix (.ardour in English) */
812 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
814 /* make a backup copy of the old file */
816 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
817 // create_backup_file will log the error
823 /* pending save: use pending_suffix (.pending in English) */
824 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
827 std::string tmp_path(_session_dir->root_path());
828 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
830 cerr << "actually writing state to " << tmp_path << endl;
832 if (!tree.write (tmp_path)) {
833 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
834 if (g_remove (tmp_path.c_str()) != 0) {
835 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
836 tmp_path, g_strerror (errno)) << endmsg;
842 cerr << "renaming state to " << xml_path << endl;
844 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
845 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
846 tmp_path, xml_path, g_strerror(errno)) << endmsg;
847 if (g_remove (tmp_path.c_str()) != 0) {
848 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
849 tmp_path, g_strerror (errno)) << endmsg;
857 save_history (snapshot_name);
859 bool was_dirty = dirty();
861 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
864 DirtyChanged (); /* EMIT SIGNAL */
867 StateSaved (snapshot_name); /* EMIT SIGNAL */
874 Session::restore_state (string snapshot_name)
876 if (load_state (snapshot_name) == 0) {
877 set_state (*state_tree->root(), Stateful::loading_state_version);
884 Session::load_state (string snapshot_name)
889 state_was_pending = false;
891 /* check for leftover pending state from a crashed capture attempt */
893 std::string xmlpath(_session_dir->root_path());
894 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
896 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
898 /* there is pending state from a crashed capture attempt */
900 boost::optional<int> r = AskAboutPendingState();
901 if (r.get_value_or (1)) {
902 state_was_pending = true;
906 if (!state_was_pending) {
907 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
910 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
911 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
912 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
913 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
918 state_tree = new XMLTree;
922 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
924 if (!state_tree->read (xmlpath)) {
925 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
931 XMLNode& root (*state_tree->root());
933 if (root.name() != X_("Session")) {
934 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
940 const XMLProperty* prop;
942 if ((prop = root.property ("version")) == 0) {
943 /* no version implies very old version of Ardour */
944 Stateful::loading_state_version = 1000;
946 if (prop->value().find ('.') != string::npos) {
947 /* old school version format */
948 if (prop->value()[0] == '2') {
949 Stateful::loading_state_version = 2000;
951 Stateful::loading_state_version = 3000;
954 Stateful::loading_state_version = atoi (prop->value());
958 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
960 std::string backup_path(_session_dir->root_path());
961 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
962 backup_path = Glib::build_filename (backup_path, backup_filename);
964 // only create a backup for a given statefile version once
966 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
968 VersionMismatch (xmlpath, backup_path);
970 if (!copy_file (xmlpath, backup_path)) {;
980 Session::load_options (const XMLNode& node)
982 LocaleGuard lg (X_("C"));
983 config.set_variables (node);
988 Session::save_default_options ()
990 return config.save_state();
1000 Session::get_template()
1002 /* if we don't disable rec-enable, diskstreams
1003 will believe they need to store their capture
1004 sources in their state node.
1007 disable_record (false);
1009 return state(false);
1013 Session::state (bool full_state)
1015 XMLNode* node = new XMLNode("Session");
1019 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1020 node->add_property("version", buf);
1022 /* store configuration settings */
1026 node->add_property ("name", _name);
1027 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
1028 node->add_property ("sample-rate", buf);
1030 if (session_dirs.size() > 1) {
1034 vector<space_and_path>::iterator i = session_dirs.begin();
1035 vector<space_and_path>::iterator next;
1037 ++i; /* skip the first one */
1041 while (i != session_dirs.end()) {
1045 if (next != session_dirs.end()) {
1046 p += G_SEARCHPATH_SEPARATOR;
1055 child = node->add_child ("Path");
1056 child->add_content (p);
1060 /* save the ID counter */
1062 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1063 node->add_property ("id-counter", buf);
1065 /* save the event ID counter */
1067 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1068 node->add_property ("event-counter", buf);
1070 /* various options */
1072 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1073 if (!midi_port_nodes.empty()) {
1074 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1075 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1076 midi_port_stuff->add_child_nocopy (**n);
1078 node->add_child_nocopy (*midi_port_stuff);
1081 node->add_child_nocopy (config.get_variables ());
1083 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1085 child = node->add_child ("Sources");
1088 Glib::Threads::Mutex::Lock sl (source_lock);
1090 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1092 /* Don't save information about non-file Sources, or
1093 * about non-destructive file sources that are empty
1094 * and unused by any regions.
1097 boost::shared_ptr<FileSource> fs;
1099 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1101 if (!fs->destructive()) {
1102 if (fs->empty() && !fs->used()) {
1107 child->add_child_nocopy (siter->second->get_state());
1112 child = node->add_child ("Regions");
1115 Glib::Threads::Mutex::Lock rl (region_lock);
1116 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1117 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1118 boost::shared_ptr<Region> r = i->second;
1119 /* only store regions not attached to playlists */
1120 if (r->playlist() == 0) {
1121 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1122 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1124 child->add_child_nocopy (r->get_state ());
1129 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1131 if (!cassocs.empty()) {
1132 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1134 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1136 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1137 i->first->id().print (buf, sizeof (buf));
1138 can->add_property (X_("copy"), buf);
1139 i->second->id().print (buf, sizeof (buf));
1140 can->add_property (X_("original"), buf);
1141 ca->add_child_nocopy (*can);
1151 node->add_child_nocopy (_locations->get_state());
1154 Locations loc (*this);
1155 // for a template, just create a new Locations, populate it
1156 // with the default start and end, and get the state for that.
1157 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1158 range->set (max_framepos, 0);
1160 XMLNode& locations_state = loc.get_state();
1162 if (ARDOUR::Profile->get_trx() && _locations) {
1163 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1164 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1165 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1166 locations_state.add_child_nocopy ((*i)->get_state ());
1170 node->add_child_nocopy (locations_state);
1173 child = node->add_child ("Bundles");
1175 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1176 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1177 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1179 child->add_child_nocopy (b->get_state());
1184 child = node->add_child ("Routes");
1186 boost::shared_ptr<RouteList> r = routes.reader ();
1188 RoutePublicOrderSorter cmp;
1189 RouteList public_order (*r);
1190 public_order.sort (cmp);
1192 /* the sort should have put control outs first */
1195 assert (_monitor_out == public_order.front());
1198 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1199 if (!(*i)->is_auditioner()) {
1201 child->add_child_nocopy ((*i)->get_state());
1203 child->add_child_nocopy ((*i)->get_template());
1209 playlists->add_state (node, full_state);
1211 child = node->add_child ("RouteGroups");
1212 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1213 child->add_child_nocopy ((*i)->get_state());
1217 XMLNode* gain_child = node->add_child ("Click");
1218 gain_child->add_child_nocopy (_click_io->state (full_state));
1219 gain_child->add_child_nocopy (_click_gain->state (full_state));
1223 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1224 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1228 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1229 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1232 node->add_child_nocopy (_speakers->get_state());
1233 node->add_child_nocopy (_tempo_map->get_state());
1234 node->add_child_nocopy (get_control_protocol_state());
1237 node->add_child_copy (*_extra_xml);
1244 Session::get_control_protocol_state ()
1246 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1247 return cpm.get_state();
1251 Session::set_state (const XMLNode& node, int version)
1255 const XMLProperty* prop;
1258 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1260 if (node.name() != X_("Session")) {
1261 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1265 if ((prop = node.property ("name")) != 0) {
1266 _name = prop->value ();
1269 if ((prop = node.property (X_("sample-rate"))) != 0) {
1271 _nominal_frame_rate = atoi (prop->value());
1273 if (_nominal_frame_rate != _current_frame_rate) {
1274 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1275 if (r.get_value_or (0)) {
1281 setup_raid_path(_session_dir->root_path());
1283 if ((prop = node.property (X_("id-counter"))) != 0) {
1285 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1286 ID::init_counter (x);
1288 /* old sessions used a timebased counter, so fake
1289 the startup ID counter based on a standard
1294 ID::init_counter (now);
1297 if ((prop = node.property (X_("event-counter"))) != 0) {
1298 Evoral::init_event_id_counter (atoi (prop->value()));
1302 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1303 _midi_ports->set_midi_port_states (child->children());
1306 IO::disable_connecting ();
1308 Stateful::save_extra_xml (node);
1310 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1311 load_options (*child);
1312 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1313 load_options (*child);
1315 error << _("Session: XML state has no options section") << endmsg;
1318 if (version >= 3000) {
1319 if ((child = find_named_node (node, "Metadata")) == 0) {
1320 warning << _("Session: XML state has no metadata section") << endmsg;
1321 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1326 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1327 _speakers->set_state (*child, version);
1330 if ((child = find_named_node (node, "Sources")) == 0) {
1331 error << _("Session: XML state has no sources section") << endmsg;
1333 } else if (load_sources (*child)) {
1337 if ((child = find_named_node (node, "TempoMap")) == 0) {
1338 error << _("Session: XML state has no Tempo Map section") << endmsg;
1340 } else if (_tempo_map->set_state (*child, version)) {
1344 if ((child = find_named_node (node, "Locations")) == 0) {
1345 error << _("Session: XML state has no locations section") << endmsg;
1347 } else if (_locations->set_state (*child, version)) {
1351 locations_changed ();
1353 if (_session_range_location) {
1354 AudioFileSource::set_header_position_offset (_session_range_location->start());
1357 if ((child = find_named_node (node, "Regions")) == 0) {
1358 error << _("Session: XML state has no Regions section") << endmsg;
1360 } else if (load_regions (*child)) {
1364 if ((child = find_named_node (node, "Playlists")) == 0) {
1365 error << _("Session: XML state has no playlists section") << endmsg;
1367 } else if (playlists->load (*this, *child)) {
1371 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1373 } else if (playlists->load_unused (*this, *child)) {
1377 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1378 if (load_compounds (*child)) {
1383 if (version >= 3000) {
1384 if ((child = find_named_node (node, "Bundles")) == 0) {
1385 warning << _("Session: XML state has no bundles section") << endmsg;
1388 /* We can't load Bundles yet as they need to be able
1389 to convert from port names to Port objects, which can't happen until
1391 _bundle_xml_node = new XMLNode (*child);
1395 if (version < 3000) {
1396 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1397 error << _("Session: XML state has no diskstreams section") << endmsg;
1399 } else if (load_diskstreams_2X (*child, version)) {
1404 if ((child = find_named_node (node, "Routes")) == 0) {
1405 error << _("Session: XML state has no routes section") << endmsg;
1407 } else if (load_routes (*child, version)) {
1411 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1412 _diskstreams_2X.clear ();
1414 if (version >= 3000) {
1416 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1417 error << _("Session: XML state has no route groups section") << endmsg;
1419 } else if (load_route_groups (*child, version)) {
1423 } else if (version < 3000) {
1425 if ((child = find_named_node (node, "EditGroups")) == 0) {
1426 error << _("Session: XML state has no edit groups section") << endmsg;
1428 } else if (load_route_groups (*child, version)) {
1432 if ((child = find_named_node (node, "MixGroups")) == 0) {
1433 error << _("Session: XML state has no mix groups section") << endmsg;
1435 } else if (load_route_groups (*child, version)) {
1440 if ((child = find_named_node (node, "Click")) == 0) {
1441 warning << _("Session: XML state has no click section") << endmsg;
1442 } else if (_click_io) {
1443 setup_click_state (&node);
1446 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1447 ControlProtocolManager::instance().set_state (*child, version);
1450 update_route_record_state ();
1452 /* here beginneth the second phase ... */
1454 StateReady (); /* EMIT SIGNAL */
1467 Session::load_routes (const XMLNode& node, int version)
1470 XMLNodeConstIterator niter;
1471 RouteList new_routes;
1473 nlist = node.children();
1477 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1479 boost::shared_ptr<Route> route;
1480 if (version < 3000) {
1481 route = XMLRouteFactory_2X (**niter, version);
1483 route = XMLRouteFactory (**niter, version);
1487 error << _("Session: cannot create Route from XML description.") << endmsg;
1491 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1493 new_routes.push_back (route);
1496 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1498 add_routes (new_routes, false, false, false);
1500 BootMessage (_("Finished adding tracks/busses"));
1505 boost::shared_ptr<Route>
1506 Session::XMLRouteFactory (const XMLNode& node, int version)
1508 boost::shared_ptr<Route> ret;
1510 if (node.name() != "Route") {
1514 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1516 DataType type = DataType::AUDIO;
1517 const XMLProperty* prop = node.property("default-type");
1520 type = DataType (prop->value());
1523 assert (type != DataType::NIL);
1527 boost::shared_ptr<Track> track;
1529 if (type == DataType::AUDIO) {
1530 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1532 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1535 if (track->init()) {
1539 if (track->set_state (node, version)) {
1543 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1544 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1549 enum Route::Flag flags = Route::Flag(0);
1550 const XMLProperty* prop = node.property("flags");
1552 flags = Route::Flag (string_2_enum (prop->value(), flags));
1555 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1557 if (r->init () == 0 && r->set_state (node, version) == 0) {
1558 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1559 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1568 boost::shared_ptr<Route>
1569 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1571 boost::shared_ptr<Route> ret;
1573 if (node.name() != "Route") {
1577 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1579 ds_prop = node.property (X_("diskstream"));
1582 DataType type = DataType::AUDIO;
1583 const XMLProperty* prop = node.property("default-type");
1586 type = DataType (prop->value());
1589 assert (type != DataType::NIL);
1593 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1594 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1598 if (i == _diskstreams_2X.end()) {
1599 error << _("Could not find diskstream for route") << endmsg;
1600 return boost::shared_ptr<Route> ();
1603 boost::shared_ptr<Track> track;
1605 if (type == DataType::AUDIO) {
1606 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1608 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1611 if (track->init()) {
1615 if (track->set_state (node, version)) {
1619 track->set_diskstream (*i);
1621 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1622 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1627 enum Route::Flag flags = Route::Flag(0);
1628 const XMLProperty* prop = node.property("flags");
1630 flags = Route::Flag (string_2_enum (prop->value(), flags));
1633 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1635 if (r->init () == 0 && r->set_state (node, version) == 0) {
1636 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1637 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1647 Session::load_regions (const XMLNode& node)
1650 XMLNodeConstIterator niter;
1651 boost::shared_ptr<Region> region;
1653 nlist = node.children();
1657 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1658 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1659 error << _("Session: cannot create Region from XML description.");
1660 const XMLProperty *name = (**niter).property("name");
1663 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1674 Session::load_compounds (const XMLNode& node)
1676 XMLNodeList calist = node.children();
1677 XMLNodeConstIterator caiter;
1678 XMLProperty *caprop;
1680 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1681 XMLNode* ca = *caiter;
1685 if ((caprop = ca->property (X_("original"))) == 0) {
1688 orig_id = caprop->value();
1690 if ((caprop = ca->property (X_("copy"))) == 0) {
1693 copy_id = caprop->value();
1695 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1696 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1698 if (!orig || !copy) {
1699 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1705 RegionFactory::add_compound_association (orig, copy);
1712 Session::load_nested_sources (const XMLNode& node)
1715 XMLNodeConstIterator niter;
1717 nlist = node.children();
1719 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1720 if ((*niter)->name() == "Source") {
1722 /* it may already exist, so don't recreate it unnecessarily
1725 XMLProperty* prop = (*niter)->property (X_("id"));
1727 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1731 ID source_id (prop->value());
1733 if (!source_by_id (source_id)) {
1736 SourceFactory::create (*this, **niter, true);
1738 catch (failed_constructor& err) {
1739 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1746 boost::shared_ptr<Region>
1747 Session::XMLRegionFactory (const XMLNode& node, bool full)
1749 const XMLProperty* type = node.property("type");
1753 const XMLNodeList& nlist = node.children();
1755 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1756 XMLNode *child = (*niter);
1757 if (child->name() == "NestedSource") {
1758 load_nested_sources (*child);
1762 if (!type || type->value() == "audio") {
1763 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1764 } else if (type->value() == "midi") {
1765 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1768 } catch (failed_constructor& err) {
1769 return boost::shared_ptr<Region> ();
1772 return boost::shared_ptr<Region> ();
1775 boost::shared_ptr<AudioRegion>
1776 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1778 const XMLProperty* prop;
1779 boost::shared_ptr<Source> source;
1780 boost::shared_ptr<AudioSource> as;
1782 SourceList master_sources;
1783 uint32_t nchans = 1;
1786 if (node.name() != X_("Region")) {
1787 return boost::shared_ptr<AudioRegion>();
1790 if ((prop = node.property (X_("channels"))) != 0) {
1791 nchans = atoi (prop->value().c_str());
1794 if ((prop = node.property ("name")) == 0) {
1795 cerr << "no name for this region\n";
1799 if ((prop = node.property (X_("source-0"))) == 0) {
1800 if ((prop = node.property ("source")) == 0) {
1801 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1802 return boost::shared_ptr<AudioRegion>();
1806 PBD::ID s_id (prop->value());
1808 if ((source = source_by_id (s_id)) == 0) {
1809 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1810 return boost::shared_ptr<AudioRegion>();
1813 as = boost::dynamic_pointer_cast<AudioSource>(source);
1815 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1816 return boost::shared_ptr<AudioRegion>();
1819 sources.push_back (as);
1821 /* pickup other channels */
1823 for (uint32_t n=1; n < nchans; ++n) {
1824 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1825 if ((prop = node.property (buf)) != 0) {
1827 PBD::ID id2 (prop->value());
1829 if ((source = source_by_id (id2)) == 0) {
1830 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1831 return boost::shared_ptr<AudioRegion>();
1834 as = boost::dynamic_pointer_cast<AudioSource>(source);
1836 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1837 return boost::shared_ptr<AudioRegion>();
1839 sources.push_back (as);
1843 for (uint32_t n = 0; n < nchans; ++n) {
1844 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1845 if ((prop = node.property (buf)) != 0) {
1847 PBD::ID id2 (prop->value());
1849 if ((source = source_by_id (id2)) == 0) {
1850 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1851 return boost::shared_ptr<AudioRegion>();
1854 as = boost::dynamic_pointer_cast<AudioSource>(source);
1856 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1857 return boost::shared_ptr<AudioRegion>();
1859 master_sources.push_back (as);
1864 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1866 /* a final detail: this is the one and only place that we know how long missing files are */
1868 if (region->whole_file()) {
1869 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1870 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1872 sfp->set_length (region->length());
1877 if (!master_sources.empty()) {
1878 if (master_sources.size() != nchans) {
1879 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1881 region->set_master_sources (master_sources);
1889 catch (failed_constructor& err) {
1890 return boost::shared_ptr<AudioRegion>();
1894 boost::shared_ptr<MidiRegion>
1895 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1897 const XMLProperty* prop;
1898 boost::shared_ptr<Source> source;
1899 boost::shared_ptr<MidiSource> ms;
1902 if (node.name() != X_("Region")) {
1903 return boost::shared_ptr<MidiRegion>();
1906 if ((prop = node.property ("name")) == 0) {
1907 cerr << "no name for this region\n";
1911 if ((prop = node.property (X_("source-0"))) == 0) {
1912 if ((prop = node.property ("source")) == 0) {
1913 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1914 return boost::shared_ptr<MidiRegion>();
1918 PBD::ID s_id (prop->value());
1920 if ((source = source_by_id (s_id)) == 0) {
1921 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1922 return boost::shared_ptr<MidiRegion>();
1925 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1927 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1928 return boost::shared_ptr<MidiRegion>();
1931 sources.push_back (ms);
1934 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1935 /* a final detail: this is the one and only place that we know how long missing files are */
1937 if (region->whole_file()) {
1938 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1939 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1941 sfp->set_length (region->length());
1949 catch (failed_constructor& err) {
1950 return boost::shared_ptr<MidiRegion>();
1955 Session::get_sources_as_xml ()
1958 XMLNode* node = new XMLNode (X_("Sources"));
1959 Glib::Threads::Mutex::Lock lm (source_lock);
1961 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1962 node->add_child_nocopy (i->second->get_state());
1969 Session::reset_write_sources (bool mark_write_complete, bool force)
1971 boost::shared_ptr<RouteList> rl = routes.reader();
1972 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1973 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1975 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1976 tr->reset_write_sources(mark_write_complete, force);
1977 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1983 Session::load_sources (const XMLNode& node)
1986 XMLNodeConstIterator niter;
1987 boost::shared_ptr<Source> source; /* don't need this but it stops some
1988 * versions of gcc complaining about
1989 * discarded return values.
1992 nlist = node.children();
1996 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1999 if ((source = XMLSourceFactory (**niter)) == 0) {
2000 error << _("Session: cannot create Source from XML description.") << endmsg;
2003 } catch (MissingSource& err) {
2007 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2008 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2009 PROGRAM_NAME) << endmsg;
2013 if (!no_questions_about_missing_files) {
2014 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2019 switch (user_choice) {
2021 /* user added a new search location, so try again */
2026 /* user asked to quit the entire session load
2031 no_questions_about_missing_files = true;
2035 no_questions_about_missing_files = true;
2042 case DataType::AUDIO:
2043 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2046 case DataType::MIDI:
2047 /* The MIDI file is actually missing so
2048 * just create a new one in the same
2049 * location. Do not announce its
2053 if (!Glib::path_is_absolute (err.path)) {
2054 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2056 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2061 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2062 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2063 /* reset ID to match the missing one */
2064 source->set_id (**niter);
2065 /* Now we can announce it */
2066 SourceFactory::SourceCreated (source);
2077 boost::shared_ptr<Source>
2078 Session::XMLSourceFactory (const XMLNode& node)
2080 if (node.name() != "Source") {
2081 return boost::shared_ptr<Source>();
2085 /* note: do peak building in another thread when loading session state */
2086 return SourceFactory::create (*this, node, true);
2089 catch (failed_constructor& err) {
2090 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2091 return boost::shared_ptr<Source>();
2096 Session::save_template (string template_name)
2098 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2102 bool absolute_path = Glib::path_is_absolute (template_name);
2104 /* directory to put the template in */
2105 std::string template_dir_path;
2107 if (!absolute_path) {
2108 std::string user_template_dir(user_template_directory());
2110 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2111 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2112 user_template_dir, g_strerror (errno)) << endmsg;
2116 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2118 template_dir_path = template_name;
2121 if (!ARDOUR::Profile->get_trx()) {
2122 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2123 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2124 template_dir_path) << endmsg;
2128 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2129 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2130 template_dir_path, g_strerror (errno)) << endmsg;
2136 std::string template_file_path;
2138 if (ARDOUR::Profile->get_trx()) {
2139 template_file_path = template_name;
2141 if (absolute_path) {
2142 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2144 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2148 SessionSaveUnderway (); /* EMIT SIGNAL */
2152 tree.set_root (&get_template());
2153 if (!tree.write (template_file_path)) {
2154 error << _("template not saved") << endmsg;
2158 if (!ARDOUR::Profile->get_trx()) {
2159 /* copy plugin state directory */
2161 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2163 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2164 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2165 template_plugin_state_path, g_strerror (errno)) << endmsg;
2168 copy_files (plugins_dir(), template_plugin_state_path);
2171 store_recent_templates (template_file_path);
2177 Session::refresh_disk_space ()
2179 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2181 Glib::Threads::Mutex::Lock lm (space_lock);
2183 /* get freespace on every FS that is part of the session path */
2185 _total_free_4k_blocks = 0;
2186 _total_free_4k_blocks_uncertain = false;
2188 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2190 struct statfs statfsbuf;
2191 statfs (i->path.c_str(), &statfsbuf);
2193 double const scale = statfsbuf.f_bsize / 4096.0;
2195 /* See if this filesystem is read-only */
2196 struct statvfs statvfsbuf;
2197 statvfs (i->path.c_str(), &statvfsbuf);
2199 /* f_bavail can be 0 if it is undefined for whatever
2200 filesystem we are looking at; Samba shares mounted
2201 via GVFS are an example of this.
2203 if (statfsbuf.f_bavail == 0) {
2204 /* block count unknown */
2206 i->blocks_unknown = true;
2207 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2208 /* read-only filesystem */
2210 i->blocks_unknown = false;
2212 /* read/write filesystem with known space */
2213 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2214 i->blocks_unknown = false;
2217 _total_free_4k_blocks += i->blocks;
2218 if (i->blocks_unknown) {
2219 _total_free_4k_blocks_uncertain = true;
2222 #elif defined PLATFORM_WINDOWS
2223 vector<string> scanned_volumes;
2224 vector<string>::iterator j;
2225 vector<space_and_path>::iterator i;
2226 DWORD nSectorsPerCluster, nBytesPerSector,
2227 nFreeClusters, nTotalClusters;
2231 _total_free_4k_blocks = 0;
2233 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2234 strncpy (disk_drive, (*i).path.c_str(), 3);
2238 volume_found = false;
2239 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2241 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2242 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2243 i->blocks = (uint32_t)(nFreeBytes / 4096);
2245 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2246 if (0 == j->compare(disk_drive)) {
2247 volume_found = true;
2252 if (!volume_found) {
2253 scanned_volumes.push_back(disk_drive);
2254 _total_free_4k_blocks += i->blocks;
2259 if (0 == _total_free_4k_blocks) {
2260 strncpy (disk_drive, path().c_str(), 3);
2263 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2265 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2266 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2267 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2274 Session::get_best_session_directory_for_new_audio ()
2276 vector<space_and_path>::iterator i;
2277 string result = _session_dir->root_path();
2279 /* handle common case without system calls */
2281 if (session_dirs.size() == 1) {
2285 /* OK, here's the algorithm we're following here:
2287 We want to select which directory to use for
2288 the next file source to be created. Ideally,
2289 we'd like to use a round-robin process so as to
2290 get maximum performance benefits from splitting
2291 the files across multiple disks.
2293 However, in situations without much diskspace, an
2294 RR approach may end up filling up a filesystem
2295 with new files while others still have space.
2296 Its therefore important to pay some attention to
2297 the freespace in the filesystem holding each
2298 directory as well. However, if we did that by
2299 itself, we'd keep creating new files in the file
2300 system with the most space until it was as full
2301 as all others, thus negating any performance
2302 benefits of this RAID-1 like approach.
2304 So, we use a user-configurable space threshold. If
2305 there are at least 2 filesystems with more than this
2306 much space available, we use RR selection between them.
2307 If not, then we pick the filesystem with the most space.
2309 This gets a good balance between the two
2313 refresh_disk_space ();
2315 int free_enough = 0;
2317 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2318 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2323 if (free_enough >= 2) {
2324 /* use RR selection process, ensuring that the one
2328 i = last_rr_session_dir;
2331 if (++i == session_dirs.end()) {
2332 i = session_dirs.begin();
2335 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2336 SessionDirectory sdir(i->path);
2337 if (sdir.create ()) {
2339 last_rr_session_dir = i;
2344 } while (i != last_rr_session_dir);
2348 /* pick FS with the most freespace (and that
2349 seems to actually work ...)
2352 vector<space_and_path> sorted;
2353 space_and_path_ascending_cmp cmp;
2355 sorted = session_dirs;
2356 sort (sorted.begin(), sorted.end(), cmp);
2358 for (i = sorted.begin(); i != sorted.end(); ++i) {
2359 SessionDirectory sdir(i->path);
2360 if (sdir.create ()) {
2362 last_rr_session_dir = i;
2372 Session::automation_dir () const
2374 return Glib::build_filename (_path, automation_dir_name);
2378 Session::analysis_dir () const
2380 return Glib::build_filename (_path, analysis_dir_name);
2384 Session::plugins_dir () const
2386 return Glib::build_filename (_path, plugins_dir_name);
2390 Session::externals_dir () const
2392 return Glib::build_filename (_path, externals_dir_name);
2396 Session::load_bundles (XMLNode const & node)
2398 XMLNodeList nlist = node.children();
2399 XMLNodeConstIterator niter;
2403 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2404 if ((*niter)->name() == "InputBundle") {
2405 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2406 } else if ((*niter)->name() == "OutputBundle") {
2407 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2409 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2418 Session::load_route_groups (const XMLNode& node, int version)
2420 XMLNodeList nlist = node.children();
2421 XMLNodeConstIterator niter;
2425 if (version >= 3000) {
2427 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2428 if ((*niter)->name() == "RouteGroup") {
2429 RouteGroup* rg = new RouteGroup (*this, "");
2430 add_route_group (rg);
2431 rg->set_state (**niter, version);
2435 } else if (version < 3000) {
2437 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2438 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2439 RouteGroup* rg = new RouteGroup (*this, "");
2440 add_route_group (rg);
2441 rg->set_state (**niter, version);
2450 state_file_filter (const string &str, void* /*arg*/)
2452 return (str.length() > strlen(statefile_suffix) &&
2453 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2457 remove_end(string state)
2459 string statename(state);
2461 string::size_type start,end;
2462 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2463 statename = statename.substr (start+1);
2466 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2467 end = statename.length();
2470 return string(statename.substr (0, end));
2474 Session::possible_states (string path)
2476 vector<string> states;
2477 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2479 transform(states.begin(), states.end(), states.begin(), remove_end);
2481 sort (states.begin(), states.end());
2487 Session::possible_states () const
2489 return possible_states(_path);
2493 Session::add_route_group (RouteGroup* g)
2495 _route_groups.push_back (g);
2496 route_group_added (g); /* EMIT SIGNAL */
2498 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2499 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2500 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2506 Session::remove_route_group (RouteGroup& rg)
2508 list<RouteGroup*>::iterator i;
2510 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2511 _route_groups.erase (i);
2514 route_group_removed (); /* EMIT SIGNAL */
2518 /** Set a new order for our route groups, without adding or removing any.
2519 * @param groups Route group list in the new order.
2522 Session::reorder_route_groups (list<RouteGroup*> groups)
2524 _route_groups = groups;
2526 route_groups_reordered (); /* EMIT SIGNAL */
2532 Session::route_group_by_name (string name)
2534 list<RouteGroup *>::iterator i;
2536 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2537 if ((*i)->name() == name) {
2545 Session::all_route_group() const
2547 return *_all_route_group;
2551 Session::add_commands (vector<Command*> const & cmds)
2553 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2559 Session::add_command (Command* const cmd)
2561 assert (_current_trans);
2562 DEBUG_UNDO_HISTORY (
2563 string_compose ("Current Undo Transaction %1, adding command: %2",
2564 _current_trans->name (),
2566 _current_trans->add_command (cmd);
2569 Session::begin_reversible_command (const string& name)
2571 begin_reversible_command (g_quark_from_string (name.c_str ()));
2574 /** Begin a reversible command using a GQuark to identify it.
2575 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2576 * but there must be as many begin...()s as there are commit...()s.
2579 Session::begin_reversible_command (GQuark q)
2581 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2582 to hold all the commands that are committed. This keeps the order of
2583 commands correct in the history.
2586 if (_current_trans == 0) {
2587 DEBUG_UNDO_HISTORY (string_compose (
2588 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2590 /* start a new transaction */
2591 assert (_current_trans_quarks.empty ());
2592 _current_trans = new UndoTransaction();
2593 _current_trans->set_name (g_quark_to_string (q));
2595 DEBUG_UNDO_HISTORY (
2596 string_compose ("Begin Reversible Command, current transaction: %1",
2597 _current_trans->name ()));
2600 _current_trans_quarks.push_front (q);
2604 Session::abort_reversible_command ()
2606 if (_current_trans != 0) {
2607 DEBUG_UNDO_HISTORY (
2608 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2609 _current_trans->clear();
2610 delete _current_trans;
2612 _current_trans_quarks.clear();
2617 Session::commit_reversible_command (Command *cmd)
2619 assert (_current_trans);
2620 assert (!_current_trans_quarks.empty ());
2625 DEBUG_UNDO_HISTORY (
2626 string_compose ("Current Undo Transaction %1, adding command: %2",
2627 _current_trans->name (),
2629 _current_trans->add_command (cmd);
2632 DEBUG_UNDO_HISTORY (
2633 string_compose ("Commit Reversible Command, current transaction: %1",
2634 _current_trans->name ()));
2636 _current_trans_quarks.pop_front ();
2638 if (!_current_trans_quarks.empty ()) {
2639 DEBUG_UNDO_HISTORY (
2640 string_compose ("Commit Reversible Command, transaction is not "
2641 "top-level, current transaction: %1",
2642 _current_trans->name ()));
2643 /* the transaction we're committing is not the top-level one */
2647 if (_current_trans->empty()) {
2648 /* no commands were added to the transaction, so just get rid of it */
2649 DEBUG_UNDO_HISTORY (
2650 string_compose ("Commit Reversible Command, No commands were "
2651 "added to current transaction: %1",
2652 _current_trans->name ()));
2653 delete _current_trans;
2658 gettimeofday (&now, 0);
2659 _current_trans->set_timestamp (now);
2661 _history.add (_current_trans);
2666 accept_all_audio_files (const string& path, void* /*arg*/)
2668 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2672 if (!AudioFileSource::safe_audio_file_extension (path)) {
2680 accept_all_midi_files (const string& path, void* /*arg*/)
2682 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2686 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2687 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2688 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2692 accept_all_state_files (const string& path, void* /*arg*/)
2694 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2698 std::string const statefile_ext (statefile_suffix);
2699 if (path.length() >= statefile_ext.length()) {
2700 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2707 Session::find_all_sources (string path, set<string>& result)
2712 if (!tree.read (path)) {
2716 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2721 XMLNodeConstIterator niter;
2723 nlist = node->children();
2727 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2731 if ((prop = (*niter)->property (X_("type"))) == 0) {
2735 DataType type (prop->value());
2737 if ((prop = (*niter)->property (X_("name"))) == 0) {
2741 if (Glib::path_is_absolute (prop->value())) {
2742 /* external file, ignore */
2750 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2751 result.insert (found_path);
2759 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2761 vector<string> state_files;
2763 string this_snapshot_path;
2769 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2770 ripped = ripped.substr (0, ripped.length() - 1);
2773 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2775 if (state_files.empty()) {
2780 this_snapshot_path = _path;
2781 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2782 this_snapshot_path += statefile_suffix;
2784 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2786 if (exclude_this_snapshot && *i == this_snapshot_path) {
2790 if (find_all_sources (*i, result) < 0) {
2798 struct RegionCounter {
2799 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2800 AudioSourceList::iterator iter;
2801 boost::shared_ptr<Region> region;
2804 RegionCounter() : count (0) {}
2808 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2810 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2811 return r.get_value_or (1);
2815 Session::cleanup_regions ()
2817 bool removed = false;
2818 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2820 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2822 uint32_t used = playlists->region_use_count (i->second);
2824 if (used == 0 && !i->second->automatic ()) {
2825 boost::weak_ptr<Region> w = i->second;
2828 RegionFactory::map_remove (w);
2835 // re-check to remove parent references of compound regions
2836 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2837 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2841 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2842 if (0 == playlists->region_use_count (i->second)) {
2843 boost::weak_ptr<Region> w = i->second;
2845 RegionFactory::map_remove (w);
2852 /* dump the history list */
2859 Session::can_cleanup_peakfiles () const
2861 if (deletion_in_progress()) {
2864 if (!_writable || (_state_of_the_state & CannotSave)) {
2865 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2868 if (record_status() == Recording) {
2869 error << _("Cannot cleanup peak-files while recording") << endmsg;
2876 Session::cleanup_peakfiles ()
2878 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2883 assert (can_cleanup_peakfiles ());
2884 assert (!peaks_cleanup_in_progres());
2886 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2888 int timeout = 5000; // 5 seconds
2889 while (!SourceFactory::files_with_peaks.empty()) {
2890 Glib::usleep (1000);
2891 if (--timeout < 0) {
2892 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2893 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2898 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2899 boost::shared_ptr<AudioSource> as;
2900 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2901 as->close_peakfile();
2905 PBD::clear_directory (session_directory().peak_path());
2907 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2909 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2910 boost::shared_ptr<AudioSource> as;
2911 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2912 SourceFactory::setup_peakfile(as, true);
2919 Session::cleanup_sources (CleanupReport& rep)
2921 // FIXME: needs adaptation to midi
2923 vector<boost::shared_ptr<Source> > dead_sources;
2926 vector<string> candidates;
2927 vector<string> unused;
2928 set<string> all_sources;
2937 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2939 /* consider deleting all unused playlists */
2941 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2946 /* sync the "all regions" property of each playlist with its current state
2949 playlists->sync_all_regions_with_regions ();
2951 /* find all un-used sources */
2956 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2958 SourceMap::iterator tmp;
2963 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2967 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2968 dead_sources.push_back (i->second);
2969 i->second->drop_references ();
2975 /* build a list of all the possible audio directories for the session */
2977 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2978 SessionDirectory sdir ((*i).path);
2979 asp += sdir.sound_path();
2981 audio_path += asp.to_string();
2984 /* build a list of all the possible midi directories for the session */
2986 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2987 SessionDirectory sdir ((*i).path);
2988 msp += sdir.midi_path();
2990 midi_path += msp.to_string();
2992 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2993 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2995 /* find all sources, but don't use this snapshot because the
2996 state file on disk still references sources we may have already
3000 find_all_sources_across_snapshots (all_sources, true);
3002 /* add our current source list
3005 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3006 boost::shared_ptr<FileSource> fs;
3007 SourceMap::iterator tmp = i;
3010 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3012 if (!fs->is_stub()) {
3014 if (playlists->source_use_count (fs) != 0) {
3015 all_sources.insert (fs->path());
3018 /* we might not remove this source from disk, because it may be used
3019 by other snapshots, but its not being used in this version
3020 so lets get rid of it now, along with any representative regions
3024 RegionFactory::remove_regions_using_source (i->second);
3026 // also remove source from all_sources
3028 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3029 spath = Glib::path_get_basename (*j);
3030 if (spath == i->second->name()) {
3031 all_sources.erase (j);
3044 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3049 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3051 tmppath1 = canonical_path (spath);
3052 tmppath2 = canonical_path ((*i));
3054 if (tmppath1 == tmppath2) {
3061 unused.push_back (spath);
3065 /* now try to move all unused files into the "dead" directory(ies) */
3067 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3068 struct stat statbuf;
3072 /* don't move the file across filesystems, just
3073 stick it in the `dead_dir_name' directory
3074 on whichever filesystem it was already on.
3077 if ((*x).find ("/sounds/") != string::npos) {
3079 /* old school, go up 1 level */
3081 newpath = Glib::path_get_dirname (*x); // "sounds"
3082 newpath = Glib::path_get_dirname (newpath); // "session-name"
3086 /* new school, go up 4 levels */
3088 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3089 newpath = Glib::path_get_dirname (newpath); // "session-name"
3090 newpath = Glib::path_get_dirname (newpath); // "interchange"
3091 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3094 newpath = Glib::build_filename (newpath, dead_dir_name);
3096 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3097 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3101 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3103 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3105 /* the new path already exists, try versioning */
3107 char buf[PATH_MAX+1];
3111 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3114 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3115 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3119 if (version == 999) {
3120 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3124 newpath = newpath_v;
3129 /* it doesn't exist, or we can't read it or something */
3133 stat ((*x).c_str(), &statbuf);
3135 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3136 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3137 (*x), newpath, strerror (errno))
3142 /* see if there an easy to find peakfile for this file, and remove it.
3145 string base = Glib::path_get_basename (*x);
3146 base += "%A"; /* this is what we add for the channel suffix of all native files,
3147 or for the first channel of embedded files. it will miss
3148 some peakfiles for other channels
3150 string peakpath = construct_peak_filepath (base);
3152 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3153 if (::g_unlink (peakpath.c_str()) != 0) {
3154 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3155 peakpath, _path, strerror (errno))
3157 /* try to back out */
3158 ::rename (newpath.c_str(), _path.c_str());
3163 rep.paths.push_back (*x);
3164 rep.space += statbuf.st_size;
3167 /* dump the history list */
3171 /* save state so we don't end up a session file
3172 referring to non-existent sources.
3179 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3185 Session::cleanup_trash_sources (CleanupReport& rep)
3187 // FIXME: needs adaptation for MIDI
3189 vector<space_and_path>::iterator i;
3195 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3197 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3199 clear_directory (dead_dir, &rep.space, &rep.paths);
3206 Session::set_dirty ()
3208 /* never mark session dirty during loading */
3210 if (_state_of_the_state & Loading) {
3214 bool was_dirty = dirty();
3216 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3220 DirtyChanged(); /* EMIT SIGNAL */
3226 Session::set_clean ()
3228 bool was_dirty = dirty();
3230 _state_of_the_state = Clean;
3234 DirtyChanged(); /* EMIT SIGNAL */
3239 Session::set_deletion_in_progress ()
3241 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3245 Session::clear_deletion_in_progress ()
3247 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3251 Session::add_controllable (boost::shared_ptr<Controllable> c)
3253 /* this adds a controllable to the list managed by the Session.
3254 this is a subset of those managed by the Controllable class
3255 itself, and represents the only ones whose state will be saved
3256 as part of the session.
3259 Glib::Threads::Mutex::Lock lm (controllables_lock);
3260 controllables.insert (c);
3263 struct null_deleter { void operator()(void const *) const {} };
3266 Session::remove_controllable (Controllable* c)
3268 if (_state_of_the_state & Deletion) {
3272 Glib::Threads::Mutex::Lock lm (controllables_lock);
3274 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3276 if (x != controllables.end()) {
3277 controllables.erase (x);
3281 boost::shared_ptr<Controllable>
3282 Session::controllable_by_id (const PBD::ID& id)
3284 Glib::Threads::Mutex::Lock lm (controllables_lock);
3286 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3287 if ((*i)->id() == id) {
3292 return boost::shared_ptr<Controllable>();
3295 boost::shared_ptr<Controllable>
3296 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3298 boost::shared_ptr<Controllable> c;
3299 boost::shared_ptr<Route> r;
3301 switch (desc.top_level_type()) {
3302 case ControllableDescriptor::NamedRoute:
3304 std::string str = desc.top_level_name();
3305 if (str == "Master" || str == "master") {
3307 } else if (str == "control" || str == "listen") {
3310 r = route_by_name (desc.top_level_name());
3315 case ControllableDescriptor::RemoteControlID:
3316 r = route_by_remote_id (desc.rid());
3324 switch (desc.subtype()) {
3325 case ControllableDescriptor::Gain:
3326 c = r->gain_control ();
3329 case ControllableDescriptor::Trim:
3330 c = r->trim()->gain_control ();
3333 case ControllableDescriptor::Solo:
3334 c = r->solo_control();
3337 case ControllableDescriptor::Mute:
3338 c = r->mute_control();
3341 case ControllableDescriptor::Recenable:
3343 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3346 c = t->rec_enable_control ();
3351 case ControllableDescriptor::PanDirection:
3353 c = r->pannable()->pan_azimuth_control;
3357 case ControllableDescriptor::PanWidth:
3359 c = r->pannable()->pan_width_control;
3363 case ControllableDescriptor::PanElevation:
3365 c = r->pannable()->pan_elevation_control;
3369 case ControllableDescriptor::Balance:
3370 /* XXX simple pan control */
3373 case ControllableDescriptor::PluginParameter:
3375 uint32_t plugin = desc.target (0);
3376 uint32_t parameter_index = desc.target (1);
3378 /* revert to zero based counting */
3384 if (parameter_index > 0) {
3388 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3391 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3392 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3397 case ControllableDescriptor::SendGain:
3399 uint32_t send = desc.target (0);
3401 /* revert to zero-based counting */
3407 boost::shared_ptr<Processor> p = r->nth_send (send);
3410 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3411 boost::shared_ptr<Amp> a = s->amp();
3414 c = s->amp()->gain_control();
3421 /* relax and return a null pointer */
3429 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3432 Stateful::add_instant_xml (node, _path);
3435 if (write_to_config) {
3436 Config->add_instant_xml (node);
3441 Session::instant_xml (const string& node_name)
3443 return Stateful::instant_xml (node_name, _path);
3447 Session::save_history (string snapshot_name)
3455 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3456 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3460 if (snapshot_name.empty()) {
3461 snapshot_name = _current_snapshot_name;
3464 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3465 const string backup_filename = history_filename + backup_suffix;
3466 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3467 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3469 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3470 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3471 error << _("could not backup old history file, current history not saved") << endmsg;
3476 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3478 if (!tree.write (xml_path))
3480 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3482 if (g_remove (xml_path.c_str()) != 0) {
3483 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3484 xml_path, g_strerror (errno)) << endmsg;
3486 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3487 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3488 backup_path, g_strerror (errno)) << endmsg;
3498 Session::restore_history (string snapshot_name)
3502 if (snapshot_name.empty()) {
3503 snapshot_name = _current_snapshot_name;
3506 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3507 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3509 info << "Loading history from " << xml_path << endmsg;
3511 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3512 info << string_compose (_("%1: no history file \"%2\" for this session."),
3513 _name, xml_path) << endmsg;
3517 if (!tree.read (xml_path)) {
3518 error << string_compose (_("Could not understand session history file \"%1\""),
3519 xml_path) << endmsg;
3526 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3529 UndoTransaction* ut = new UndoTransaction ();
3532 ut->set_name(t->property("name")->value());
3533 stringstream ss(t->property("tv-sec")->value());
3535 ss.str(t->property("tv-usec")->value());
3537 ut->set_timestamp(tv);
3539 for (XMLNodeConstIterator child_it = t->children().begin();
3540 child_it != t->children().end(); child_it++)
3542 XMLNode *n = *child_it;
3545 if (n->name() == "MementoCommand" ||
3546 n->name() == "MementoUndoCommand" ||
3547 n->name() == "MementoRedoCommand") {
3549 if ((c = memento_command_factory(n))) {
3553 } else if (n->name() == "NoteDiffCommand") {
3554 PBD::ID id (n->property("midi-source")->value());
3555 boost::shared_ptr<MidiSource> midi_source =
3556 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3558 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3560 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3563 } else if (n->name() == "SysExDiffCommand") {
3565 PBD::ID id (n->property("midi-source")->value());
3566 boost::shared_ptr<MidiSource> midi_source =
3567 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3569 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3571 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3574 } else if (n->name() == "PatchChangeDiffCommand") {
3576 PBD::ID id (n->property("midi-source")->value());
3577 boost::shared_ptr<MidiSource> midi_source =
3578 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3580 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3582 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3585 } else if (n->name() == "StatefulDiffCommand") {
3586 if ((c = stateful_diff_command_factory (n))) {
3587 ut->add_command (c);
3590 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3601 Session::config_changed (std::string p, bool ours)
3607 if (p == "seamless-loop") {
3609 } else if (p == "rf-speed") {
3611 } else if (p == "auto-loop") {
3613 } else if (p == "auto-input") {
3615 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3616 /* auto-input only makes a difference if we're rolling */
3617 set_track_monitor_input_status (!config.get_auto_input());
3620 } else if (p == "punch-in") {
3624 if ((location = _locations->auto_punch_location()) != 0) {
3626 if (config.get_punch_in ()) {
3627 replace_event (SessionEvent::PunchIn, location->start());
3629 remove_event (location->start(), SessionEvent::PunchIn);
3633 } else if (p == "punch-out") {
3637 if ((location = _locations->auto_punch_location()) != 0) {
3639 if (config.get_punch_out()) {
3640 replace_event (SessionEvent::PunchOut, location->end());
3642 clear_events (SessionEvent::PunchOut);
3646 } else if (p == "edit-mode") {
3648 Glib::Threads::Mutex::Lock lm (playlists->lock);
3650 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3651 (*i)->set_edit_mode (Config->get_edit_mode ());
3654 } else if (p == "use-video-sync") {
3656 waiting_for_sync_offset = config.get_use_video_sync();
3658 } else if (p == "mmc-control") {
3660 //poke_midi_thread ();
3662 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3664 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3666 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3668 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3670 } else if (p == "midi-control") {
3672 //poke_midi_thread ();
3674 } else if (p == "raid-path") {
3676 setup_raid_path (config.get_raid_path());
3678 } else if (p == "timecode-format") {
3682 } else if (p == "video-pullup") {
3686 } else if (p == "seamless-loop") {
3688 if (play_loop && transport_rolling()) {
3689 // to reset diskstreams etc
3690 request_play_loop (true);
3693 } else if (p == "rf-speed") {
3695 cumulative_rf_motion = 0;
3698 } else if (p == "click-sound") {
3700 setup_click_sounds (1);
3702 } else if (p == "click-emphasis-sound") {
3704 setup_click_sounds (-1);
3706 } else if (p == "clicking") {
3708 if (Config->get_clicking()) {
3709 if (_click_io && click_data) { // don't require emphasis data
3716 } else if (p == "click-gain") {
3719 _click_gain->set_gain (Config->get_click_gain(), this);
3722 } else if (p == "send-mtc") {
3724 if (Config->get_send_mtc ()) {
3725 /* mark us ready to send */
3726 next_quarter_frame_to_send = 0;
3729 } else if (p == "send-mmc") {
3731 _mmc->enable_send (Config->get_send_mmc ());
3733 } else if (p == "midi-feedback") {
3735 session_midi_feedback = Config->get_midi_feedback();
3737 } else if (p == "jack-time-master") {
3739 engine().reset_timebase ();
3741 } else if (p == "native-file-header-format") {
3743 if (!first_file_header_format_reset) {
3744 reset_native_file_format ();
3747 first_file_header_format_reset = false;
3749 } else if (p == "native-file-data-format") {
3751 if (!first_file_data_format_reset) {
3752 reset_native_file_format ();
3755 first_file_data_format_reset = false;
3757 } else if (p == "external-sync") {
3758 if (!config.get_external_sync()) {
3759 drop_sync_source ();
3761 switch_to_sync_source (Config->get_sync_source());
3763 } else if (p == "denormal-model") {
3765 } else if (p == "history-depth") {
3766 set_history_depth (Config->get_history_depth());
3767 } else if (p == "remote-model") {
3768 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3771 } else if (p == "initial-program-change") {
3773 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3776 buf[0] = MIDI::program; // channel zero by default
3777 buf[1] = (Config->get_initial_program_change() & 0x7f);
3779 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3781 } else if (p == "solo-mute-override") {
3782 // catch_up_on_solo_mute_override ();
3783 } else if (p == "listen-position" || p == "pfl-position") {
3784 listen_position_changed ();
3785 } else if (p == "solo-control-is-listen-control") {
3786 solo_control_mode_changed ();
3787 } else if (p == "solo-mute-gain") {
3788 _solo_cut_control->Changed();
3789 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3790 last_timecode_valid = false;
3791 } else if (p == "playback-buffer-seconds") {
3792 AudioSource::allocate_working_buffers (frame_rate());
3793 } else if (p == "ltc-source-port") {
3794 reconnect_ltc_input ();
3795 } else if (p == "ltc-sink-port") {
3796 reconnect_ltc_output ();
3797 } else if (p == "timecode-generator-offset") {
3798 ltc_tx_parse_offset();
3799 } else if (p == "auto-return-target-list") {
3800 follow_playhead_priority ();
3807 Session::set_history_depth (uint32_t d)
3809 _history.set_depth (d);
3813 Session::load_diskstreams_2X (XMLNode const & node, int)
3816 XMLNodeConstIterator citer;
3818 clist = node.children();
3820 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3823 /* diskstreams added automatically by DiskstreamCreated handler */
3824 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3825 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3826 _diskstreams_2X.push_back (dsp);
3828 error << _("Session: unknown diskstream type in XML") << endmsg;
3832 catch (failed_constructor& err) {
3833 error << _("Session: could not load diskstream via XML state") << endmsg;
3841 /** Connect things to the MMC object */
3843 Session::setup_midi_machine_control ()
3845 _mmc = new MIDI::MachineControl;
3846 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3848 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3849 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3850 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3851 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3852 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3853 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3854 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3855 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3856 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3857 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3858 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3859 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3860 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3862 /* also handle MIDI SPP because its so common */
3864 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3865 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3866 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3869 boost::shared_ptr<Controllable>
3870 Session::solo_cut_control() const
3872 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3873 controls in Ardour that currently get presented to the user in the GUI that require
3874 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3876 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3877 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3881 return _solo_cut_control;
3885 Session::rename (const std::string& new_name)
3887 string legal_name = legalize_for_path (new_name);
3893 string const old_sources_root = _session_dir->sources_root();
3895 if (!_writable || (_state_of_the_state & CannotSave)) {
3896 error << _("Cannot rename read-only session.") << endmsg;
3897 return 0; // don't show "messed up" warning
3899 if (record_status() == Recording) {
3900 error << _("Cannot rename session while recording") << endmsg;
3901 return 0; // don't show "messed up" warning
3904 StateProtector stp (this);
3909 * interchange subdirectory
3913 * Backup files are left unchanged and not renamed.
3916 /* Windows requires that we close all files before attempting the
3917 * rename. This works on other platforms, but isn't necessary there.
3918 * Leave it in place for all platforms though, since it may help
3919 * catch issues that could arise if the way Source files work ever
3920 * change (since most developers are not using Windows).
3923 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3924 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3930 /* pass one: not 100% safe check that the new directory names don't
3934 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3938 /* this is a stupid hack because Glib::path_get_dirname() is
3939 * lexical-only, and so passing it /a/b/c/ gives a different
3940 * result than passing it /a/b/c ...
3943 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3944 oldstr = oldstr.substr (0, oldstr.length() - 1);
3947 string base = Glib::path_get_dirname (oldstr);
3949 newstr = Glib::build_filename (base, legal_name);
3951 cerr << "Looking for " << newstr << endl;
3953 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3954 cerr << " exists\n";
3963 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3969 /* this is a stupid hack because Glib::path_get_dirname() is
3970 * lexical-only, and so passing it /a/b/c/ gives a different
3971 * result than passing it /a/b/c ...
3974 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3975 oldstr = oldstr.substr (0, oldstr.length() - 1);
3978 string base = Glib::path_get_dirname (oldstr);
3979 newstr = Glib::build_filename (base, legal_name);
3981 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3983 cerr << "Rename " << oldstr << " => " << newstr << endl;
3984 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3985 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3986 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3990 /* Reset path in "session dirs" */
3995 /* reset primary SessionDirectory object */
3998 (*_session_dir) = newstr;
4003 /* now rename directory below session_dir/interchange */
4005 string old_interchange_dir;
4006 string new_interchange_dir;
4008 /* use newstr here because we renamed the path
4009 * (folder/directory) that used to be oldstr to newstr above
4012 v.push_back (newstr);
4013 v.push_back (interchange_dir_name);
4014 v.push_back (Glib::path_get_basename (oldstr));
4016 old_interchange_dir = Glib::build_filename (v);
4019 v.push_back (newstr);
4020 v.push_back (interchange_dir_name);
4021 v.push_back (legal_name);
4023 new_interchange_dir = Glib::build_filename (v);
4025 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4027 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4028 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4029 old_interchange_dir, new_interchange_dir,
4032 error << string_compose (_("renaming %s as %2 failed (%3)"),
4033 old_interchange_dir, new_interchange_dir,
4042 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4043 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4045 cerr << "Rename " << oldstr << " => " << newstr << endl;
4047 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4048 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4049 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4055 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4057 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4058 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4060 cerr << "Rename " << oldstr << " => " << newstr << endl;
4062 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4063 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4064 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4069 /* remove old name from recent sessions */
4070 remove_recent_sessions (_path);
4073 /* update file source paths */
4075 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4076 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4078 string p = fs->path ();
4079 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4081 SourceFactory::setup_peakfile(i->second, true);
4085 _current_snapshot_name = new_name;
4090 /* save state again to get everything just right */
4092 save_state (_current_snapshot_name);
4094 /* add to recent sessions */
4096 store_recent_sessions (new_name, _path);
4102 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4104 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4108 if (!tree.read (xmlpath)) {
4116 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4119 bool found_sr = false;
4120 bool found_data_format = false;
4122 if (get_session_info_from_path (tree, xmlpath)) {
4128 const XMLProperty* prop;
4129 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
4130 sample_rate = atoi (prop->value());
4134 const XMLNodeList& children (tree.root()->children());
4135 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4136 const XMLNode* child = *c;
4137 if (child->name() == "Config") {
4138 const XMLNodeList& options (child->children());
4139 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4140 const XMLNode* option = *oc;
4141 const XMLProperty* name = option->property("name");
4147 if (name->value() == "native-file-data-format") {
4148 const XMLProperty* value = option->property ("value");
4150 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4152 found_data_format = true;
4158 if (found_data_format) {
4163 return !(found_sr && found_data_format); // zero if they are both found
4166 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4167 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4170 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4174 SourcePathMap source_path_map;
4176 boost::shared_ptr<AudioFileSource> afs;
4181 Glib::Threads::Mutex::Lock lm (source_lock);
4183 cerr << " total sources = " << sources.size();
4185 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4186 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4192 if (fs->within_session()) {
4196 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4197 source_path_map[fs->path()].push_back (fs);
4199 SeveralFileSources v;
4201 source_path_map.insert (make_pair (fs->path(), v));
4207 cerr << " fsources = " << total << endl;
4209 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4211 /* tell caller where we are */
4213 string old_path = i->first;
4215 callback (n, total, old_path);
4217 cerr << old_path << endl;
4221 switch (i->second.front()->type()) {
4222 case DataType::AUDIO:
4223 new_path = new_audio_source_path_for_embedded (old_path);
4226 case DataType::MIDI:
4227 /* XXX not implemented yet */
4231 if (new_path.empty()) {
4235 cerr << "Move " << old_path << " => " << new_path << endl;
4237 if (!copy_file (old_path, new_path)) {
4238 cerr << "failed !\n";
4242 /* make sure we stop looking in the external
4243 dir/folder. Remember, this is an all-or-nothing
4244 operations, it doesn't merge just some files.
4246 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4248 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4249 (*f)->set_path (new_path);
4254 save_state ("", false, false);
4260 bool accept_all_files (string const &, void *)
4266 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4268 /* 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.
4273 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4275 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4277 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4279 v.push_back (new_session_folder); /* full path */
4280 v.push_back (interchange_dir_name);
4281 v.push_back (new_session_path); /* just one directory/folder */
4282 v.push_back (typedir);
4283 v.push_back (Glib::path_get_basename (old_path));
4285 return Glib::build_filename (v);
4289 Session::save_as (SaveAs& saveas)
4291 vector<string> files;
4292 string current_folder = Glib::path_get_dirname (_path);
4293 string new_folder = legalize_for_path (saveas.new_name);
4294 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4295 int64_t total_bytes = 0;
4299 int32_t internal_file_cnt = 0;
4301 vector<string> do_not_copy_extensions;
4302 do_not_copy_extensions.push_back (statefile_suffix);
4303 do_not_copy_extensions.push_back (pending_suffix);
4304 do_not_copy_extensions.push_back (backup_suffix);
4305 do_not_copy_extensions.push_back (temp_suffix);
4306 do_not_copy_extensions.push_back (history_suffix);
4308 /* get total size */
4310 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4312 /* need to clear this because
4313 * find_files_matching_filter() is cumulative
4318 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4320 all += files.size();
4322 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4324 g_stat ((*i).c_str(), &gsb);
4325 total_bytes += gsb.st_size;
4329 /* save old values so we can switch back if we are not switching to the new session */
4331 string old_path = _path;
4332 string old_name = _name;
4333 string old_snapshot = _current_snapshot_name;
4334 string old_sd = _session_dir->root_path();
4335 vector<string> old_search_path[DataType::num_types];
4336 string old_config_search_path[DataType::num_types];
4338 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4339 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4340 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4341 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4343 /* switch session directory */
4345 (*_session_dir) = to_dir;
4347 /* create new tree */
4349 if (!_session_dir->create()) {
4350 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4355 /* copy all relevant files. Find each location in session_dirs,
4356 * and copy files from there to target.
4359 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4361 /* need to clear this because
4362 * find_files_matching_filter() is cumulative
4367 const size_t prefix_len = (*sd).path.size();
4369 /* Work just on the files within this session dir */
4371 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4373 /* add dir separator to protect against collisions with
4374 * track names (e.g. track named "audiofiles" or
4378 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4379 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4380 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4382 /* copy all the files. Handling is different for media files
4383 than others because of the *silly* subtree we have below the interchange
4384 folder. That really was a bad idea, but I'm not fixing it as part of
4385 implementing ::save_as().
4388 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4390 std::string from = *i;
4393 string filename = Glib::path_get_basename (from);
4394 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4395 if (filename == ".DS_STORE") {
4400 if (from.find (audiofile_dir_string) != string::npos) {
4402 /* audio file: only copy if asked */
4404 if (saveas.include_media && saveas.copy_media) {
4406 string to = make_new_media_path (*i, to_dir, new_folder);
4408 info << "media file copying from " << from << " to " << to << endmsg;
4410 if (!copy_file (from, to)) {
4411 throw Glib::FileError (Glib::FileError::IO_ERROR,
4412 string_compose(_("\ncopying \"%1\" failed !"), from));
4416 /* we found media files inside the session folder */
4418 internal_file_cnt++;
4420 } else if (from.find (midifile_dir_string) != string::npos) {
4422 /* midi file: always copy unless
4423 * creating an empty new session
4426 if (saveas.include_media) {
4428 string to = make_new_media_path (*i, to_dir, new_folder);
4430 info << "media file copying from " << from << " to " << to << endmsg;
4432 if (!copy_file (from, to)) {
4433 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4437 /* we found media files inside the session folder */
4439 internal_file_cnt++;
4441 } else if (from.find (analysis_dir_string) != string::npos) {
4443 /* make sure analysis dir exists in
4444 * new session folder, but we're not
4445 * copying analysis files here, see
4449 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4454 /* normal non-media file. Don't copy state, history, etc.
4457 bool do_copy = true;
4459 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4460 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4461 /* end of filename matches extension, do not copy file */
4467 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4468 /* don't copy peakfiles if
4469 * we're not copying media
4475 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4477 info << "attempting to make directory/folder " << to << endmsg;
4479 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4480 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4483 info << "attempting to copy " << from << " to " << to << endmsg;
4485 if (!copy_file (from, to)) {
4486 throw Glib::FileError (Glib::FileError::IO_ERROR,
4487 string_compose(_("\ncopying \"%1\" failed !"), from));
4492 /* measure file size even if we're not going to copy so that our Progress
4493 signals are correct, since we included these do-not-copy files
4494 in the computation of the total size and file count.
4498 g_stat (from.c_str(), &gsb);
4499 copied += gsb.st_size;
4502 double fraction = (double) copied / total_bytes;
4504 bool keep_going = true;
4506 if (saveas.copy_media) {
4508 /* no need or expectation of this if
4509 * media is not being copied, because
4510 * it will be fast(ish).
4513 /* tell someone "X percent, file M of N"; M is one-based */
4515 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4523 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4529 /* copy optional folders, if any */
4531 string old = plugins_dir ();
4532 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4533 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4534 copy_files (old, newdir);
4537 old = externals_dir ();
4538 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4539 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4540 copy_files (old, newdir);
4543 old = automation_dir ();
4544 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4545 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4546 copy_files (old, newdir);
4549 if (saveas.include_media) {
4551 if (saveas.copy_media) {
4552 #ifndef PLATFORM_WINDOWS
4553 /* There are problems with analysis files on
4554 * Windows, because they used a colon in their
4555 * names as late as 4.0. Colons are not legal
4556 * under Windows even if NTFS allows them.
4558 * This is a tricky problem to solve so for
4559 * just don't copy these files. They will be
4560 * regenerated as-needed anyway, subject to the
4561 * existing issue that the filenames will be
4562 * rejected by Windows, which is a separate
4563 * problem (though related).
4566 /* only needed if we are copying media, since the
4567 * analysis data refers to media data
4570 old = analysis_dir ();
4571 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4572 string newdir = Glib::build_filename (to_dir, "analysis");
4573 copy_files (old, newdir);
4575 #endif /* PLATFORM_WINDOWS */
4581 _current_snapshot_name = saveas.new_name;
4582 _name = saveas.new_name;
4584 if (saveas.include_media && !saveas.copy_media) {
4586 /* reset search paths of the new session (which we're pretending to be right now) to
4587 include the original session search path, so we can still find all audio.
4590 if (internal_file_cnt) {
4591 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4592 ensure_search_path_includes (*s, DataType::AUDIO);
4593 cerr << "be sure to include " << *s << " for audio" << endl;
4596 /* we do not do this for MIDI because we copy
4597 all MIDI files if saveas.include_media is
4603 bool was_dirty = dirty ();
4605 save_state ("", false, false, !saveas.include_media);
4606 save_default_options ();
4608 if (saveas.copy_media && saveas.copy_external) {
4609 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4610 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4614 saveas.final_session_folder_name = _path;
4616 store_recent_sessions (_name, _path);
4618 if (!saveas.switch_to) {
4620 /* switch back to the way things were */
4624 _current_snapshot_name = old_snapshot;
4626 (*_session_dir) = old_sd;
4632 if (internal_file_cnt) {
4633 /* reset these to their original values */
4634 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4635 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4640 /* prune session dirs, and update disk space statistics
4645 session_dirs.clear ();
4646 session_dirs.push_back (sp);
4647 refresh_disk_space ();
4649 /* ensure that all existing tracks reset their current capture source paths
4651 reset_write_sources (true, true);
4653 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4654 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4657 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4658 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4664 if (fs->within_session()) {
4665 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4666 fs->set_path (newpath);
4671 } catch (Glib::FileError& e) {
4673 saveas.failure_message = e.what();
4675 /* recursively remove all the directories */
4677 remove_directory (to_dir);
4685 saveas.failure_message = _("unknown reason");
4687 /* recursively remove all the directories */
4689 remove_directory (to_dir);