2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #include <sys/param.h>
43 #include <sys/mount.h>
46 #ifdef HAVE_SYS_STATVFS_H
47 #include <sys/statvfs.h>
51 #include <pbd/gstdio_compat.h>
54 #include <glibmm/threads.h>
55 #include <glibmm/fileutils.h>
57 #include <boost/algorithm/string.hpp>
59 #include "midi++/mmc.h"
60 #include "midi++/port.h"
62 #include "evoral/SMF.hpp"
64 #include "pbd/boost_debug.h"
65 #include "pbd/basename.h"
66 #include "pbd/controllable_descriptor.h"
67 #include "pbd/debug.h"
68 #include "pbd/enumwriter.h"
69 #include "pbd/error.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/localtime_r.h"
77 #include "ardour/amp.h"
78 #include "ardour/async_midi_port.h"
79 #include "ardour/audio_diskstream.h"
80 #include "ardour/audio_track.h"
81 #include "ardour/audioengine.h"
82 #include "ardour/audiofilesource.h"
83 #include "ardour/audioregion.h"
84 #include "ardour/automation_control.h"
85 #include "ardour/butler.h"
86 #include "ardour/control_protocol_manager.h"
87 #include "ardour/directory_names.h"
88 #include "ardour/filename_extensions.h"
89 #include "ardour/graph.h"
90 #include "ardour/location.h"
91 #include "ardour/midi_model.h"
92 #include "ardour/midi_patch_manager.h"
93 #include "ardour/midi_region.h"
94 #include "ardour/midi_scene_changer.h"
95 #include "ardour/midi_source.h"
96 #include "ardour/midi_track.h"
97 #include "ardour/pannable.h"
98 #include "ardour/playlist_factory.h"
99 #include "ardour/playlist_source.h"
100 #include "ardour/port.h"
101 #include "ardour/processor.h"
102 #include "ardour/profile.h"
103 #include "ardour/proxy_controllable.h"
104 #include "ardour/recent_sessions.h"
105 #include "ardour/region_factory.h"
106 #include "ardour/route_group.h"
107 #include "ardour/send.h"
108 #include "ardour/session.h"
109 #include "ardour/session_directory.h"
110 #include "ardour/session_metadata.h"
111 #include "ardour/session_playlists.h"
112 #include "ardour/session_state_utils.h"
113 #include "ardour/silentfilesource.h"
114 #include "ardour/sndfilesource.h"
115 #include "ardour/source_factory.h"
116 #include "ardour/speakers.h"
117 #include "ardour/template_utils.h"
118 #include "ardour/tempo.h"
119 #include "ardour/ticker.h"
120 #include "ardour/user_bundle.h"
122 #include "control_protocol/control_protocol.h"
128 using namespace ARDOUR;
131 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
134 Session::pre_engine_init (string fullpath)
136 if (fullpath.empty()) {
138 throw failed_constructor();
141 /* discover canonical fullpath */
143 _path = canonical_path(fullpath);
146 if (Profile->get_trx() ) {
147 // Waves TracksLive has a usecase of session replacement with a new one.
148 // We should check session state file (<session_name>.ardour) existance
149 // to determine if the session is new or not
151 string full_session_name = Glib::build_filename( fullpath, _name );
152 full_session_name += statefile_suffix;
154 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
156 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
159 /* finish initialization that can't be done in a normal C++ constructor
163 timerclear (&last_mmc_step);
164 g_atomic_int_set (&processing_prohibited, 0);
165 g_atomic_int_set (&_record_status, Disabled);
166 g_atomic_int_set (&_playback_load, 100);
167 g_atomic_int_set (&_capture_load, 100);
169 _all_route_group->set_active (true, this);
170 interpolation.add_channel_to (0, 0);
172 if (config.get_use_video_sync()) {
173 waiting_for_sync_offset = true;
175 waiting_for_sync_offset = false;
178 last_rr_session_dir = session_dirs.begin();
180 set_history_depth (Config->get_history_depth());
182 /* default: assume simple stereo speaker configuration */
184 _speakers->setup_default_speakers (2);
186 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
187 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
188 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
189 add_controllable (_solo_cut_control);
191 /* These are all static "per-class" signals */
193 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
194 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
195 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
196 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
197 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
199 /* stop IO objects from doing stuff until we're ready for them */
201 Delivery::disable_panners ();
202 IO::disable_connecting ();
206 Session::post_engine_init ()
208 BootMessage (_("Set block size and sample rate"));
210 set_block_size (_engine.samples_per_cycle());
211 set_frame_rate (_engine.sample_rate());
213 BootMessage (_("Using configuration"));
215 _midi_ports = new MidiPortManager;
217 MIDISceneChanger* msc;
219 _scene_changer = msc = new MIDISceneChanger (*this);
220 msc->set_input_port (scene_input_port());
221 msc->set_output_port (scene_out());
223 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
224 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
226 setup_midi_machine_control ();
228 if (_butler->start_thread()) {
232 if (start_midi_thread ()) {
236 setup_click_sounds (0);
237 setup_midi_control ();
239 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
240 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
243 /* tempo map requires sample rate knowledge */
246 _tempo_map = new TempoMap (_current_frame_rate);
247 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
249 /* MidiClock requires a tempo map */
251 midi_clock = new MidiClockTicker ();
252 midi_clock->set_session (this);
254 /* crossfades require sample rate knowledge */
256 SndFileSource::setup_standard_crossfades (*this, frame_rate());
257 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
259 AudioDiskstream::allocate_working_buffers();
260 refresh_disk_space ();
262 /* we're finally ready to call set_state() ... all objects have
263 * been created, the engine is running.
267 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
271 // set_state() will call setup_raid_path(), but if it's a new session we need
272 // to call setup_raid_path() here.
273 setup_raid_path (_path);
278 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
279 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
281 Config->map_parameters (ff);
282 config.map_parameters (ft);
283 _butler->map_parameters ();
285 /* Reset all panners */
287 Delivery::reset_panners ();
289 /* this will cause the CPM to instantiate any protocols that are in use
290 * (or mandatory), which will pass it this Session, and then call
291 * set_state() on each instantiated protocol to match stored state.
294 ControlProtocolManager::instance().set_session (this);
296 /* This must be done after the ControlProtocolManager set_session above,
297 as it will set states for ports which the ControlProtocolManager creates.
300 // XXX set state of MIDI::Port's
301 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
303 /* And this must be done after the MIDI::Manager::set_port_states as
304 * it will try to make connections whose details are loaded by set_port_states.
309 /* Let control protocols know that we are now all connected, so they
310 * could start talking to surfaces if they want to.
313 ControlProtocolManager::instance().midi_connectivity_established ();
315 if (_is_new && !no_auto_connect()) {
316 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
317 auto_connect_master_bus ();
320 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
322 /* update latencies */
324 initialize_latencies ();
326 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
327 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
328 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
330 } catch (AudioEngine::PortRegistrationFailure& err) {
331 /* handle this one in a different way than all others, so that its clear what happened */
332 error << err.what() << endmsg;
338 BootMessage (_("Reset Remote Controls"));
340 // send_full_time_code (0);
341 _engine.transport_locate (0);
343 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
344 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
346 MIDI::Name::MidiPatchManager::instance().set_session (this);
349 /* initial program change will be delivered later; see ::config_changed() */
351 _state_of_the_state = Clean;
353 Port::set_connecting_blocked (false);
355 DirtyChanged (); /* EMIT SIGNAL */
359 } else if (state_was_pending) {
361 remove_pending_capture_state ();
362 state_was_pending = false;
365 /* Now, finally, we can fill the playback buffers */
367 BootMessage (_("Filling playback buffers"));
369 boost::shared_ptr<RouteList> rl = routes.reader();
370 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
371 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
372 if (trk && !trk->hidden()) {
373 trk->seek (_transport_frame, true);
381 Session::session_loaded ()
385 _state_of_the_state = Clean;
387 DirtyChanged (); /* EMIT SIGNAL */
391 } else if (state_was_pending) {
393 remove_pending_capture_state ();
394 state_was_pending = false;
397 /* Now, finally, we can fill the playback buffers */
399 BootMessage (_("Filling playback buffers"));
400 force_locate (_transport_frame, false);
404 Session::raid_path () const
406 Searchpath raid_search_path;
408 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
409 raid_search_path += (*i).path;
412 return raid_search_path.to_string ();
416 Session::setup_raid_path (string path)
425 session_dirs.clear ();
427 Searchpath search_path(path);
428 Searchpath sound_search_path;
429 Searchpath midi_search_path;
431 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
433 sp.blocks = 0; // not needed
434 session_dirs.push_back (sp);
436 SessionDirectory sdir(sp.path);
438 sound_search_path += sdir.sound_path ();
439 midi_search_path += sdir.midi_path ();
442 // reset the round-robin soundfile path thingie
443 last_rr_session_dir = session_dirs.begin();
447 Session::path_is_within_session (const std::string& path)
449 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
450 if (PBD::path_is_within (i->path, path)) {
458 Session::ensure_subdirs ()
462 dir = session_directory().peak_path();
464 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
465 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
469 dir = session_directory().sound_path();
471 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
472 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
476 dir = session_directory().midi_path();
478 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
479 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
483 dir = session_directory().dead_path();
485 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
486 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
490 dir = session_directory().export_path();
492 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
493 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
497 dir = analysis_dir ();
499 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
500 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
504 dir = plugins_dir ();
506 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
507 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
511 dir = externals_dir ();
513 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
514 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
521 /** @param session_template directory containing session template, or empty.
522 * Caller must not hold process lock.
525 Session::create (const string& session_template, BusProfile* bus_profile)
527 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
528 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
532 if (ensure_subdirs ()) {
536 _writable = exists_and_writable (_path);
538 if (!session_template.empty()) {
539 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
541 FILE* in = g_fopen (in_path.c_str(), "rb");
544 /* no need to call legalize_for_path() since the string
545 * in session_template is already a legal path name
547 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
549 FILE* out = g_fopen (out_path.c_str(), "wb");
553 stringstream new_session;
556 size_t charsRead = fread (buf, sizeof(char), 1024, in);
559 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
564 if (charsRead == 0) {
567 new_session.write (buf, charsRead);
571 string file_contents = new_session.str();
572 size_t writeSize = file_contents.length();
573 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
574 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
582 if (!ARDOUR::Profile->get_trx()) {
583 /* Copy plugin state files from template to new session */
584 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
585 copy_recurse (template_plugins, plugins_dir ());
591 error << string_compose (_("Could not open %1 for writing session template"), out_path)
598 error << string_compose (_("Could not open session template %1 for reading"), in_path)
605 if (Profile->get_trx()) {
607 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
608 Remember that this is a brand new session. Sessions
609 loaded from saved state will get this range from the saved state.
612 set_session_range_location (0, 0);
614 /* Initial loop location, from absolute zero, length 10 seconds */
616 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
617 _locations->add (loc, true);
618 set_auto_loop_location (loc);
621 _state_of_the_state = Clean;
623 /* set up Master Out and Control Out if necessary */
628 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
630 // Waves Tracks: always create master bus for Tracks
631 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
632 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
636 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
637 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
640 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
641 r->input()->ensure_io (count, false, this);
642 r->output()->ensure_io (count, false, this);
648 /* prohibit auto-connect to master, because there isn't one */
649 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
653 add_routes (rl, false, false, false);
656 // Waves Tracks: Skip this. Always use autoconnection for Tracks
657 if (!ARDOUR::Profile->get_trx()) {
659 /* this allows the user to override settings with an environment variable.
662 if (no_auto_connect()) {
663 bus_profile->input_ac = AutoConnectOption (0);
664 bus_profile->output_ac = AutoConnectOption (0);
667 Config->set_input_auto_connect (bus_profile->input_ac);
668 Config->set_output_auto_connect (bus_profile->output_ac);
672 if (Config->get_use_monitor_bus() && bus_profile) {
673 add_monitor_section ();
680 Session::maybe_write_autosave()
682 if (dirty() && record_status() != Recording) {
683 save_state("", true);
688 Session::remove_pending_capture_state ()
690 std::string pending_state_file_path(_session_dir->root_path());
692 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
694 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
696 if (g_remove (pending_state_file_path.c_str()) != 0) {
697 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
698 pending_state_file_path, g_strerror (errno)) << endmsg;
702 /** Rename a state file.
703 * @param old_name Old snapshot name.
704 * @param new_name New snapshot name.
707 Session::rename_state (string old_name, string new_name)
709 if (old_name == _current_snapshot_name || old_name == _name) {
710 /* refuse to rename the current snapshot or the "main" one */
714 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
715 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
717 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
718 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
720 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
721 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
722 old_name, new_name, g_strerror(errno)) << endmsg;
726 /** Remove a state file.
727 * @param snapshot_name Snapshot name.
730 Session::remove_state (string snapshot_name)
732 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
733 // refuse to remove the current snapshot or the "main" one
737 std::string xml_path(_session_dir->root_path());
739 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
741 if (!create_backup_file (xml_path)) {
742 // don't remove it if a backup can't be made
743 // create_backup_file will log the error.
748 if (g_remove (xml_path.c_str()) != 0) {
749 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
750 xml_path, g_strerror (errno)) << endmsg;
754 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
756 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
759 std::string xml_path(_session_dir->root_path());
761 /* prevent concurrent saves from different threads */
763 Glib::Threads::Mutex::Lock lm (save_state_lock);
765 if (!_writable || (_state_of_the_state & CannotSave)) {
769 if (g_atomic_int_get(&_suspend_save)) {
773 _save_queued = false;
775 if (!_engine.connected ()) {
776 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
782 /* tell sources we're saving first, in case they write out to a new file
783 * which should be saved with the state rather than the old one */
784 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
786 i->second->session_saved();
787 } catch (Evoral::SMF::FileError& e) {
788 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
792 SessionSaveUnderway (); /* EMIT SIGNAL */
795 tree.set_root (&get_template());
797 tree.set_root (&get_state());
800 if (snapshot_name.empty()) {
801 snapshot_name = _current_snapshot_name;
802 } else if (switch_to_snapshot) {
803 _current_snapshot_name = snapshot_name;
808 /* proper save: use statefile_suffix (.ardour in English) */
810 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
812 /* make a backup copy of the old file */
814 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
815 // create_backup_file will log the error
821 /* pending save: use pending_suffix (.pending in English) */
822 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
825 std::string tmp_path(_session_dir->root_path());
826 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
828 cerr << "actually writing state to " << tmp_path << endl;
830 if (!tree.write (tmp_path)) {
831 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
832 if (g_remove (tmp_path.c_str()) != 0) {
833 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
834 tmp_path, g_strerror (errno)) << endmsg;
840 cerr << "renaming state to " << xml_path << endl;
842 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
843 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
844 tmp_path, xml_path, g_strerror(errno)) << endmsg;
845 if (g_remove (tmp_path.c_str()) != 0) {
846 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
847 tmp_path, g_strerror (errno)) << endmsg;
855 save_history (snapshot_name);
857 bool was_dirty = dirty();
859 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
862 DirtyChanged (); /* EMIT SIGNAL */
865 StateSaved (snapshot_name); /* EMIT SIGNAL */
872 Session::restore_state (string snapshot_name)
874 if (load_state (snapshot_name) == 0) {
875 set_state (*state_tree->root(), Stateful::loading_state_version);
882 Session::load_state (string snapshot_name)
887 state_was_pending = false;
889 /* check for leftover pending state from a crashed capture attempt */
891 std::string xmlpath(_session_dir->root_path());
892 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
894 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
896 /* there is pending state from a crashed capture attempt */
898 boost::optional<int> r = AskAboutPendingState();
899 if (r.get_value_or (1)) {
900 state_was_pending = true;
904 if (!state_was_pending) {
905 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
908 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
909 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
910 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
911 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
916 state_tree = new XMLTree;
920 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
922 if (!state_tree->read (xmlpath)) {
923 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
929 XMLNode& root (*state_tree->root());
931 if (root.name() != X_("Session")) {
932 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
938 const XMLProperty* prop;
940 if ((prop = root.property ("version")) == 0) {
941 /* no version implies very old version of Ardour */
942 Stateful::loading_state_version = 1000;
944 if (prop->value().find ('.') != string::npos) {
945 /* old school version format */
946 if (prop->value()[0] == '2') {
947 Stateful::loading_state_version = 2000;
949 Stateful::loading_state_version = 3000;
952 Stateful::loading_state_version = atoi (prop->value());
956 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
958 std::string backup_path(_session_dir->root_path());
959 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
960 backup_path = Glib::build_filename (backup_path, backup_filename);
962 // only create a backup for a given statefile version once
964 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
966 VersionMismatch (xmlpath, backup_path);
968 if (!copy_file (xmlpath, backup_path)) {;
978 Session::load_options (const XMLNode& node)
980 LocaleGuard lg (X_("C"));
981 config.set_variables (node);
986 Session::save_default_options ()
988 return config.save_state();
998 Session::get_template()
1000 /* if we don't disable rec-enable, diskstreams
1001 will believe they need to store their capture
1002 sources in their state node.
1005 disable_record (false);
1007 return state(false);
1011 Session::state (bool full_state)
1013 XMLNode* node = new XMLNode("Session");
1017 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1018 node->add_property("version", buf);
1020 /* store configuration settings */
1024 node->add_property ("name", _name);
1025 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
1026 node->add_property ("sample-rate", buf);
1028 if (session_dirs.size() > 1) {
1032 vector<space_and_path>::iterator i = session_dirs.begin();
1033 vector<space_and_path>::iterator next;
1035 ++i; /* skip the first one */
1039 while (i != session_dirs.end()) {
1043 if (next != session_dirs.end()) {
1044 p += G_SEARCHPATH_SEPARATOR;
1053 child = node->add_child ("Path");
1054 child->add_content (p);
1058 /* save the ID counter */
1060 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1061 node->add_property ("id-counter", buf);
1063 /* save the event ID counter */
1065 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1066 node->add_property ("event-counter", buf);
1068 /* various options */
1070 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1071 if (!midi_port_nodes.empty()) {
1072 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1073 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1074 midi_port_stuff->add_child_nocopy (**n);
1076 node->add_child_nocopy (*midi_port_stuff);
1079 node->add_child_nocopy (config.get_variables ());
1081 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1083 child = node->add_child ("Sources");
1086 Glib::Threads::Mutex::Lock sl (source_lock);
1088 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1090 /* Don't save information about non-file Sources, or
1091 * about non-destructive file sources that are empty
1092 * and unused by any regions.
1095 boost::shared_ptr<FileSource> fs;
1097 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1099 if (!fs->destructive()) {
1100 if (fs->empty() && !fs->used()) {
1105 child->add_child_nocopy (siter->second->get_state());
1110 child = node->add_child ("Regions");
1113 Glib::Threads::Mutex::Lock rl (region_lock);
1114 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1115 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1116 boost::shared_ptr<Region> r = i->second;
1117 /* only store regions not attached to playlists */
1118 if (r->playlist() == 0) {
1119 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1120 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1122 child->add_child_nocopy (r->get_state ());
1127 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1129 if (!cassocs.empty()) {
1130 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1132 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1134 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1135 i->first->id().print (buf, sizeof (buf));
1136 can->add_property (X_("copy"), buf);
1137 i->second->id().print (buf, sizeof (buf));
1138 can->add_property (X_("original"), buf);
1139 ca->add_child_nocopy (*can);
1149 node->add_child_nocopy (_locations->get_state());
1152 Locations loc (*this);
1153 // for a template, just create a new Locations, populate it
1154 // with the default start and end, and get the state for that.
1155 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1156 range->set (max_framepos, 0);
1158 XMLNode& locations_state = loc.get_state();
1160 if (ARDOUR::Profile->get_trx() && _locations) {
1161 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1162 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1163 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1164 locations_state.add_child_nocopy ((*i)->get_state ());
1168 node->add_child_nocopy (locations_state);
1171 child = node->add_child ("Bundles");
1173 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1174 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1175 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1177 child->add_child_nocopy (b->get_state());
1182 child = node->add_child ("Routes");
1184 boost::shared_ptr<RouteList> r = routes.reader ();
1186 RoutePublicOrderSorter cmp;
1187 RouteList public_order (*r);
1188 public_order.sort (cmp);
1190 /* the sort should have put control outs first */
1193 assert (_monitor_out == public_order.front());
1196 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1197 if (!(*i)->is_auditioner()) {
1199 child->add_child_nocopy ((*i)->get_state());
1201 child->add_child_nocopy ((*i)->get_template());
1207 playlists->add_state (node, full_state);
1209 child = node->add_child ("RouteGroups");
1210 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1211 child->add_child_nocopy ((*i)->get_state());
1215 XMLNode* gain_child = node->add_child ("Click");
1216 gain_child->add_child_nocopy (_click_io->state (full_state));
1217 gain_child->add_child_nocopy (_click_gain->state (full_state));
1221 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1222 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1226 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1227 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1230 node->add_child_nocopy (_speakers->get_state());
1231 node->add_child_nocopy (_tempo_map->get_state());
1232 node->add_child_nocopy (get_control_protocol_state());
1235 node->add_child_copy (*_extra_xml);
1242 Session::get_control_protocol_state ()
1244 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1245 return cpm.get_state();
1249 Session::set_state (const XMLNode& node, int version)
1253 const XMLProperty* prop;
1256 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1258 if (node.name() != X_("Session")) {
1259 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1263 if ((prop = node.property ("name")) != 0) {
1264 _name = prop->value ();
1267 if ((prop = node.property (X_("sample-rate"))) != 0) {
1269 _nominal_frame_rate = atoi (prop->value());
1271 if (_nominal_frame_rate != _current_frame_rate) {
1272 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1273 if (r.get_value_or (0)) {
1279 setup_raid_path(_session_dir->root_path());
1281 if ((prop = node.property (X_("id-counter"))) != 0) {
1283 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1284 ID::init_counter (x);
1286 /* old sessions used a timebased counter, so fake
1287 the startup ID counter based on a standard
1292 ID::init_counter (now);
1295 if ((prop = node.property (X_("event-counter"))) != 0) {
1296 Evoral::init_event_id_counter (atoi (prop->value()));
1300 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1301 _midi_ports->set_midi_port_states (child->children());
1304 IO::disable_connecting ();
1306 Stateful::save_extra_xml (node);
1308 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1309 load_options (*child);
1310 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1311 load_options (*child);
1313 error << _("Session: XML state has no options section") << endmsg;
1316 if (version >= 3000) {
1317 if ((child = find_named_node (node, "Metadata")) == 0) {
1318 warning << _("Session: XML state has no metadata section") << endmsg;
1319 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1324 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1325 _speakers->set_state (*child, version);
1328 if ((child = find_named_node (node, "Sources")) == 0) {
1329 error << _("Session: XML state has no sources section") << endmsg;
1331 } else if (load_sources (*child)) {
1335 if ((child = find_named_node (node, "TempoMap")) == 0) {
1336 error << _("Session: XML state has no Tempo Map section") << endmsg;
1338 } else if (_tempo_map->set_state (*child, version)) {
1342 if ((child = find_named_node (node, "Locations")) == 0) {
1343 error << _("Session: XML state has no locations section") << endmsg;
1345 } else if (_locations->set_state (*child, version)) {
1349 locations_changed ();
1351 if (_session_range_location) {
1352 AudioFileSource::set_header_position_offset (_session_range_location->start());
1355 if ((child = find_named_node (node, "Regions")) == 0) {
1356 error << _("Session: XML state has no Regions section") << endmsg;
1358 } else if (load_regions (*child)) {
1362 if ((child = find_named_node (node, "Playlists")) == 0) {
1363 error << _("Session: XML state has no playlists section") << endmsg;
1365 } else if (playlists->load (*this, *child)) {
1369 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1371 } else if (playlists->load_unused (*this, *child)) {
1375 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1376 if (load_compounds (*child)) {
1381 if (version >= 3000) {
1382 if ((child = find_named_node (node, "Bundles")) == 0) {
1383 warning << _("Session: XML state has no bundles section") << endmsg;
1386 /* We can't load Bundles yet as they need to be able
1387 to convert from port names to Port objects, which can't happen until
1389 _bundle_xml_node = new XMLNode (*child);
1393 if (version < 3000) {
1394 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1395 error << _("Session: XML state has no diskstreams section") << endmsg;
1397 } else if (load_diskstreams_2X (*child, version)) {
1402 if ((child = find_named_node (node, "Routes")) == 0) {
1403 error << _("Session: XML state has no routes section") << endmsg;
1405 } else if (load_routes (*child, version)) {
1409 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1410 _diskstreams_2X.clear ();
1412 if (version >= 3000) {
1414 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1415 error << _("Session: XML state has no route groups section") << endmsg;
1417 } else if (load_route_groups (*child, version)) {
1421 } else if (version < 3000) {
1423 if ((child = find_named_node (node, "EditGroups")) == 0) {
1424 error << _("Session: XML state has no edit groups section") << endmsg;
1426 } else if (load_route_groups (*child, version)) {
1430 if ((child = find_named_node (node, "MixGroups")) == 0) {
1431 error << _("Session: XML state has no mix groups section") << endmsg;
1433 } else if (load_route_groups (*child, version)) {
1438 if ((child = find_named_node (node, "Click")) == 0) {
1439 warning << _("Session: XML state has no click section") << endmsg;
1440 } else if (_click_io) {
1441 setup_click_state (&node);
1444 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1445 ControlProtocolManager::instance().set_state (*child, version);
1448 update_route_record_state ();
1450 /* here beginneth the second phase ... */
1452 StateReady (); /* EMIT SIGNAL */
1465 Session::load_routes (const XMLNode& node, int version)
1468 XMLNodeConstIterator niter;
1469 RouteList new_routes;
1471 nlist = node.children();
1475 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1477 boost::shared_ptr<Route> route;
1478 if (version < 3000) {
1479 route = XMLRouteFactory_2X (**niter, version);
1481 route = XMLRouteFactory (**niter, version);
1485 error << _("Session: cannot create Route from XML description.") << endmsg;
1489 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1491 new_routes.push_back (route);
1494 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1496 add_routes (new_routes, false, false, false);
1498 BootMessage (_("Finished adding tracks/busses"));
1503 boost::shared_ptr<Route>
1504 Session::XMLRouteFactory (const XMLNode& node, int version)
1506 boost::shared_ptr<Route> ret;
1508 if (node.name() != "Route") {
1512 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1514 DataType type = DataType::AUDIO;
1515 const XMLProperty* prop = node.property("default-type");
1518 type = DataType (prop->value());
1521 assert (type != DataType::NIL);
1525 boost::shared_ptr<Track> track;
1527 if (type == DataType::AUDIO) {
1528 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1530 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1533 if (track->init()) {
1537 if (track->set_state (node, version)) {
1541 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1542 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1547 enum Route::Flag flags = Route::Flag(0);
1548 const XMLProperty* prop = node.property("flags");
1550 flags = Route::Flag (string_2_enum (prop->value(), flags));
1553 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1555 if (r->init () == 0 && r->set_state (node, version) == 0) {
1556 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1557 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1566 boost::shared_ptr<Route>
1567 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1569 boost::shared_ptr<Route> ret;
1571 if (node.name() != "Route") {
1575 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1577 ds_prop = node.property (X_("diskstream"));
1580 DataType type = DataType::AUDIO;
1581 const XMLProperty* prop = node.property("default-type");
1584 type = DataType (prop->value());
1587 assert (type != DataType::NIL);
1591 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1592 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1596 if (i == _diskstreams_2X.end()) {
1597 error << _("Could not find diskstream for route") << endmsg;
1598 return boost::shared_ptr<Route> ();
1601 boost::shared_ptr<Track> track;
1603 if (type == DataType::AUDIO) {
1604 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1606 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1609 if (track->init()) {
1613 if (track->set_state (node, version)) {
1617 track->set_diskstream (*i);
1619 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1620 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1625 enum Route::Flag flags = Route::Flag(0);
1626 const XMLProperty* prop = node.property("flags");
1628 flags = Route::Flag (string_2_enum (prop->value(), flags));
1631 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1633 if (r->init () == 0 && r->set_state (node, version) == 0) {
1634 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1635 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1645 Session::load_regions (const XMLNode& node)
1648 XMLNodeConstIterator niter;
1649 boost::shared_ptr<Region> region;
1651 nlist = node.children();
1655 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1656 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1657 error << _("Session: cannot create Region from XML description.");
1658 const XMLProperty *name = (**niter).property("name");
1661 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1672 Session::load_compounds (const XMLNode& node)
1674 XMLNodeList calist = node.children();
1675 XMLNodeConstIterator caiter;
1676 XMLProperty *caprop;
1678 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1679 XMLNode* ca = *caiter;
1683 if ((caprop = ca->property (X_("original"))) == 0) {
1686 orig_id = caprop->value();
1688 if ((caprop = ca->property (X_("copy"))) == 0) {
1691 copy_id = caprop->value();
1693 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1694 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1696 if (!orig || !copy) {
1697 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1703 RegionFactory::add_compound_association (orig, copy);
1710 Session::load_nested_sources (const XMLNode& node)
1713 XMLNodeConstIterator niter;
1715 nlist = node.children();
1717 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1718 if ((*niter)->name() == "Source") {
1720 /* it may already exist, so don't recreate it unnecessarily
1723 XMLProperty* prop = (*niter)->property (X_("id"));
1725 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1729 ID source_id (prop->value());
1731 if (!source_by_id (source_id)) {
1734 SourceFactory::create (*this, **niter, true);
1736 catch (failed_constructor& err) {
1737 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1744 boost::shared_ptr<Region>
1745 Session::XMLRegionFactory (const XMLNode& node, bool full)
1747 const XMLProperty* type = node.property("type");
1751 const XMLNodeList& nlist = node.children();
1753 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1754 XMLNode *child = (*niter);
1755 if (child->name() == "NestedSource") {
1756 load_nested_sources (*child);
1760 if (!type || type->value() == "audio") {
1761 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1762 } else if (type->value() == "midi") {
1763 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1766 } catch (failed_constructor& err) {
1767 return boost::shared_ptr<Region> ();
1770 return boost::shared_ptr<Region> ();
1773 boost::shared_ptr<AudioRegion>
1774 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1776 const XMLProperty* prop;
1777 boost::shared_ptr<Source> source;
1778 boost::shared_ptr<AudioSource> as;
1780 SourceList master_sources;
1781 uint32_t nchans = 1;
1784 if (node.name() != X_("Region")) {
1785 return boost::shared_ptr<AudioRegion>();
1788 if ((prop = node.property (X_("channels"))) != 0) {
1789 nchans = atoi (prop->value().c_str());
1792 if ((prop = node.property ("name")) == 0) {
1793 cerr << "no name for this region\n";
1797 if ((prop = node.property (X_("source-0"))) == 0) {
1798 if ((prop = node.property ("source")) == 0) {
1799 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1800 return boost::shared_ptr<AudioRegion>();
1804 PBD::ID s_id (prop->value());
1806 if ((source = source_by_id (s_id)) == 0) {
1807 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1808 return boost::shared_ptr<AudioRegion>();
1811 as = boost::dynamic_pointer_cast<AudioSource>(source);
1813 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1814 return boost::shared_ptr<AudioRegion>();
1817 sources.push_back (as);
1819 /* pickup other channels */
1821 for (uint32_t n=1; n < nchans; ++n) {
1822 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1823 if ((prop = node.property (buf)) != 0) {
1825 PBD::ID id2 (prop->value());
1827 if ((source = source_by_id (id2)) == 0) {
1828 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1829 return boost::shared_ptr<AudioRegion>();
1832 as = boost::dynamic_pointer_cast<AudioSource>(source);
1834 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1835 return boost::shared_ptr<AudioRegion>();
1837 sources.push_back (as);
1841 for (uint32_t n = 0; n < nchans; ++n) {
1842 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1843 if ((prop = node.property (buf)) != 0) {
1845 PBD::ID id2 (prop->value());
1847 if ((source = source_by_id (id2)) == 0) {
1848 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1849 return boost::shared_ptr<AudioRegion>();
1852 as = boost::dynamic_pointer_cast<AudioSource>(source);
1854 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1855 return boost::shared_ptr<AudioRegion>();
1857 master_sources.push_back (as);
1862 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1864 /* a final detail: this is the one and only place that we know how long missing files are */
1866 if (region->whole_file()) {
1867 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1868 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1870 sfp->set_length (region->length());
1875 if (!master_sources.empty()) {
1876 if (master_sources.size() != nchans) {
1877 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1879 region->set_master_sources (master_sources);
1887 catch (failed_constructor& err) {
1888 return boost::shared_ptr<AudioRegion>();
1892 boost::shared_ptr<MidiRegion>
1893 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1895 const XMLProperty* prop;
1896 boost::shared_ptr<Source> source;
1897 boost::shared_ptr<MidiSource> ms;
1900 if (node.name() != X_("Region")) {
1901 return boost::shared_ptr<MidiRegion>();
1904 if ((prop = node.property ("name")) == 0) {
1905 cerr << "no name for this region\n";
1909 if ((prop = node.property (X_("source-0"))) == 0) {
1910 if ((prop = node.property ("source")) == 0) {
1911 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1912 return boost::shared_ptr<MidiRegion>();
1916 PBD::ID s_id (prop->value());
1918 if ((source = source_by_id (s_id)) == 0) {
1919 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1920 return boost::shared_ptr<MidiRegion>();
1923 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1925 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1926 return boost::shared_ptr<MidiRegion>();
1929 sources.push_back (ms);
1932 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1933 /* a final detail: this is the one and only place that we know how long missing files are */
1935 if (region->whole_file()) {
1936 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1937 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1939 sfp->set_length (region->length());
1947 catch (failed_constructor& err) {
1948 return boost::shared_ptr<MidiRegion>();
1953 Session::get_sources_as_xml ()
1956 XMLNode* node = new XMLNode (X_("Sources"));
1957 Glib::Threads::Mutex::Lock lm (source_lock);
1959 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1960 node->add_child_nocopy (i->second->get_state());
1967 Session::reset_write_sources (bool mark_write_complete, bool force)
1969 boost::shared_ptr<RouteList> rl = routes.reader();
1970 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1971 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1973 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1974 tr->reset_write_sources(mark_write_complete, force);
1975 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1981 Session::load_sources (const XMLNode& node)
1984 XMLNodeConstIterator niter;
1985 boost::shared_ptr<Source> source; /* don't need this but it stops some
1986 * versions of gcc complaining about
1987 * discarded return values.
1990 nlist = node.children();
1994 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1997 if ((source = XMLSourceFactory (**niter)) == 0) {
1998 error << _("Session: cannot create Source from XML description.") << endmsg;
2001 } catch (MissingSource& err) {
2005 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2006 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2007 PROGRAM_NAME) << endmsg;
2011 if (!no_questions_about_missing_files) {
2012 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2017 switch (user_choice) {
2019 /* user added a new search location, so try again */
2024 /* user asked to quit the entire session load
2029 no_questions_about_missing_files = true;
2033 no_questions_about_missing_files = true;
2040 case DataType::AUDIO:
2041 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2044 case DataType::MIDI:
2045 /* The MIDI file is actually missing so
2046 * just create a new one in the same
2047 * location. Do not announce its
2051 if (!Glib::path_is_absolute (err.path)) {
2052 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2054 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2059 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2060 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2061 /* reset ID to match the missing one */
2062 source->set_id (**niter);
2063 /* Now we can announce it */
2064 SourceFactory::SourceCreated (source);
2075 boost::shared_ptr<Source>
2076 Session::XMLSourceFactory (const XMLNode& node)
2078 if (node.name() != "Source") {
2079 return boost::shared_ptr<Source>();
2083 /* note: do peak building in another thread when loading session state */
2084 return SourceFactory::create (*this, node, true);
2087 catch (failed_constructor& err) {
2088 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2089 return boost::shared_ptr<Source>();
2094 Session::save_template (string template_name)
2096 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2100 bool absolute_path = Glib::path_is_absolute (template_name);
2102 /* directory to put the template in */
2103 std::string template_dir_path;
2105 if (!absolute_path) {
2106 std::string user_template_dir(user_template_directory());
2108 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2109 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2110 user_template_dir, g_strerror (errno)) << endmsg;
2114 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2116 template_dir_path = template_name;
2119 if (!ARDOUR::Profile->get_trx()) {
2120 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2121 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2122 template_dir_path) << endmsg;
2126 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2127 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2128 template_dir_path, g_strerror (errno)) << endmsg;
2134 std::string template_file_path;
2136 if (ARDOUR::Profile->get_trx()) {
2137 template_file_path = template_name;
2139 if (absolute_path) {
2140 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2142 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2146 SessionSaveUnderway (); /* EMIT SIGNAL */
2150 tree.set_root (&get_template());
2151 if (!tree.write (template_file_path)) {
2152 error << _("template not saved") << endmsg;
2156 if (!ARDOUR::Profile->get_trx()) {
2157 /* copy plugin state directory */
2159 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2161 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2162 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2163 template_plugin_state_path, g_strerror (errno)) << endmsg;
2166 copy_files (plugins_dir(), template_plugin_state_path);
2169 store_recent_templates (template_file_path);
2175 Session::refresh_disk_space ()
2177 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2179 Glib::Threads::Mutex::Lock lm (space_lock);
2181 /* get freespace on every FS that is part of the session path */
2183 _total_free_4k_blocks = 0;
2184 _total_free_4k_blocks_uncertain = false;
2186 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2188 struct statfs statfsbuf;
2189 statfs (i->path.c_str(), &statfsbuf);
2191 double const scale = statfsbuf.f_bsize / 4096.0;
2193 /* See if this filesystem is read-only */
2194 struct statvfs statvfsbuf;
2195 statvfs (i->path.c_str(), &statvfsbuf);
2197 /* f_bavail can be 0 if it is undefined for whatever
2198 filesystem we are looking at; Samba shares mounted
2199 via GVFS are an example of this.
2201 if (statfsbuf.f_bavail == 0) {
2202 /* block count unknown */
2204 i->blocks_unknown = true;
2205 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2206 /* read-only filesystem */
2208 i->blocks_unknown = false;
2210 /* read/write filesystem with known space */
2211 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2212 i->blocks_unknown = false;
2215 _total_free_4k_blocks += i->blocks;
2216 if (i->blocks_unknown) {
2217 _total_free_4k_blocks_uncertain = true;
2220 #elif defined PLATFORM_WINDOWS
2221 vector<string> scanned_volumes;
2222 vector<string>::iterator j;
2223 vector<space_and_path>::iterator i;
2224 DWORD nSectorsPerCluster, nBytesPerSector,
2225 nFreeClusters, nTotalClusters;
2229 _total_free_4k_blocks = 0;
2231 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2232 strncpy (disk_drive, (*i).path.c_str(), 3);
2236 volume_found = false;
2237 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2239 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2240 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2241 i->blocks = (uint32_t)(nFreeBytes / 4096);
2243 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2244 if (0 == j->compare(disk_drive)) {
2245 volume_found = true;
2250 if (!volume_found) {
2251 scanned_volumes.push_back(disk_drive);
2252 _total_free_4k_blocks += i->blocks;
2257 if (0 == _total_free_4k_blocks) {
2258 strncpy (disk_drive, path().c_str(), 3);
2261 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2263 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2264 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2265 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2272 Session::get_best_session_directory_for_new_audio ()
2274 vector<space_and_path>::iterator i;
2275 string result = _session_dir->root_path();
2277 /* handle common case without system calls */
2279 if (session_dirs.size() == 1) {
2283 /* OK, here's the algorithm we're following here:
2285 We want to select which directory to use for
2286 the next file source to be created. Ideally,
2287 we'd like to use a round-robin process so as to
2288 get maximum performance benefits from splitting
2289 the files across multiple disks.
2291 However, in situations without much diskspace, an
2292 RR approach may end up filling up a filesystem
2293 with new files while others still have space.
2294 Its therefore important to pay some attention to
2295 the freespace in the filesystem holding each
2296 directory as well. However, if we did that by
2297 itself, we'd keep creating new files in the file
2298 system with the most space until it was as full
2299 as all others, thus negating any performance
2300 benefits of this RAID-1 like approach.
2302 So, we use a user-configurable space threshold. If
2303 there are at least 2 filesystems with more than this
2304 much space available, we use RR selection between them.
2305 If not, then we pick the filesystem with the most space.
2307 This gets a good balance between the two
2311 refresh_disk_space ();
2313 int free_enough = 0;
2315 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2316 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2321 if (free_enough >= 2) {
2322 /* use RR selection process, ensuring that the one
2326 i = last_rr_session_dir;
2329 if (++i == session_dirs.end()) {
2330 i = session_dirs.begin();
2333 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2334 SessionDirectory sdir(i->path);
2335 if (sdir.create ()) {
2337 last_rr_session_dir = i;
2342 } while (i != last_rr_session_dir);
2346 /* pick FS with the most freespace (and that
2347 seems to actually work ...)
2350 vector<space_and_path> sorted;
2351 space_and_path_ascending_cmp cmp;
2353 sorted = session_dirs;
2354 sort (sorted.begin(), sorted.end(), cmp);
2356 for (i = sorted.begin(); i != sorted.end(); ++i) {
2357 SessionDirectory sdir(i->path);
2358 if (sdir.create ()) {
2360 last_rr_session_dir = i;
2370 Session::automation_dir () const
2372 return Glib::build_filename (_path, automation_dir_name);
2376 Session::analysis_dir () const
2378 return Glib::build_filename (_path, analysis_dir_name);
2382 Session::plugins_dir () const
2384 return Glib::build_filename (_path, plugins_dir_name);
2388 Session::externals_dir () const
2390 return Glib::build_filename (_path, externals_dir_name);
2394 Session::load_bundles (XMLNode const & node)
2396 XMLNodeList nlist = node.children();
2397 XMLNodeConstIterator niter;
2401 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2402 if ((*niter)->name() == "InputBundle") {
2403 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2404 } else if ((*niter)->name() == "OutputBundle") {
2405 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2407 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2416 Session::load_route_groups (const XMLNode& node, int version)
2418 XMLNodeList nlist = node.children();
2419 XMLNodeConstIterator niter;
2423 if (version >= 3000) {
2425 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2426 if ((*niter)->name() == "RouteGroup") {
2427 RouteGroup* rg = new RouteGroup (*this, "");
2428 add_route_group (rg);
2429 rg->set_state (**niter, version);
2433 } else if (version < 3000) {
2435 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2436 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2437 RouteGroup* rg = new RouteGroup (*this, "");
2438 add_route_group (rg);
2439 rg->set_state (**niter, version);
2448 state_file_filter (const string &str, void* /*arg*/)
2450 return (str.length() > strlen(statefile_suffix) &&
2451 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2455 remove_end(string state)
2457 string statename(state);
2459 string::size_type start,end;
2460 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2461 statename = statename.substr (start+1);
2464 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2465 end = statename.length();
2468 return string(statename.substr (0, end));
2472 Session::possible_states (string path)
2474 vector<string> states;
2475 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2477 transform(states.begin(), states.end(), states.begin(), remove_end);
2479 sort (states.begin(), states.end());
2485 Session::possible_states () const
2487 return possible_states(_path);
2491 Session::add_route_group (RouteGroup* g)
2493 _route_groups.push_back (g);
2494 route_group_added (g); /* EMIT SIGNAL */
2496 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2497 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2498 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2504 Session::remove_route_group (RouteGroup& rg)
2506 list<RouteGroup*>::iterator i;
2508 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2509 _route_groups.erase (i);
2512 route_group_removed (); /* EMIT SIGNAL */
2516 /** Set a new order for our route groups, without adding or removing any.
2517 * @param groups Route group list in the new order.
2520 Session::reorder_route_groups (list<RouteGroup*> groups)
2522 _route_groups = groups;
2524 route_groups_reordered (); /* EMIT SIGNAL */
2530 Session::route_group_by_name (string name)
2532 list<RouteGroup *>::iterator i;
2534 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2535 if ((*i)->name() == name) {
2543 Session::all_route_group() const
2545 return *_all_route_group;
2549 Session::add_commands (vector<Command*> const & cmds)
2551 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2557 Session::add_command (Command* const cmd)
2559 assert (_current_trans);
2560 DEBUG_UNDO_HISTORY (
2561 string_compose ("Current Undo Transaction %1, adding command: %2",
2562 _current_trans->name (),
2564 _current_trans->add_command (cmd);
2567 Session::begin_reversible_command (const string& name)
2569 begin_reversible_command (g_quark_from_string (name.c_str ()));
2572 /** Begin a reversible command using a GQuark to identify it.
2573 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2574 * but there must be as many begin...()s as there are commit...()s.
2577 Session::begin_reversible_command (GQuark q)
2579 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2580 to hold all the commands that are committed. This keeps the order of
2581 commands correct in the history.
2584 if (_current_trans == 0) {
2585 DEBUG_UNDO_HISTORY (string_compose (
2586 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2588 /* start a new transaction */
2589 assert (_current_trans_quarks.empty ());
2590 _current_trans = new UndoTransaction();
2591 _current_trans->set_name (g_quark_to_string (q));
2593 DEBUG_UNDO_HISTORY (
2594 string_compose ("Begin Reversible Command, current transaction: %1",
2595 _current_trans->name ()));
2598 _current_trans_quarks.push_front (q);
2602 Session::abort_reversible_command ()
2604 if (_current_trans != 0) {
2605 DEBUG_UNDO_HISTORY (
2606 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2607 _current_trans->clear();
2608 delete _current_trans;
2610 _current_trans_quarks.clear();
2615 Session::commit_reversible_command (Command *cmd)
2617 assert (_current_trans);
2618 assert (!_current_trans_quarks.empty ());
2623 DEBUG_UNDO_HISTORY (
2624 string_compose ("Current Undo Transaction %1, adding command: %2",
2625 _current_trans->name (),
2627 _current_trans->add_command (cmd);
2630 DEBUG_UNDO_HISTORY (
2631 string_compose ("Commit Reversible Command, current transaction: %1",
2632 _current_trans->name ()));
2634 _current_trans_quarks.pop_front ();
2636 if (!_current_trans_quarks.empty ()) {
2637 DEBUG_UNDO_HISTORY (
2638 string_compose ("Commit Reversible Command, transaction is not "
2639 "top-level, current transaction: %1",
2640 _current_trans->name ()));
2641 /* the transaction we're committing is not the top-level one */
2645 if (_current_trans->empty()) {
2646 /* no commands were added to the transaction, so just get rid of it */
2647 DEBUG_UNDO_HISTORY (
2648 string_compose ("Commit Reversible Command, No commands were "
2649 "added to current transaction: %1",
2650 _current_trans->name ()));
2651 delete _current_trans;
2656 gettimeofday (&now, 0);
2657 _current_trans->set_timestamp (now);
2659 _history.add (_current_trans);
2664 accept_all_audio_files (const string& path, void* /*arg*/)
2666 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2670 if (!AudioFileSource::safe_audio_file_extension (path)) {
2678 accept_all_midi_files (const string& path, void* /*arg*/)
2680 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2684 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2685 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2686 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2690 accept_all_state_files (const string& path, void* /*arg*/)
2692 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2696 std::string const statefile_ext (statefile_suffix);
2697 if (path.length() >= statefile_ext.length()) {
2698 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2705 Session::find_all_sources (string path, set<string>& result)
2710 if (!tree.read (path)) {
2714 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2719 XMLNodeConstIterator niter;
2721 nlist = node->children();
2725 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2729 if ((prop = (*niter)->property (X_("type"))) == 0) {
2733 DataType type (prop->value());
2735 if ((prop = (*niter)->property (X_("name"))) == 0) {
2739 if (Glib::path_is_absolute (prop->value())) {
2740 /* external file, ignore */
2748 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2749 result.insert (found_path);
2757 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2759 vector<string> state_files;
2761 string this_snapshot_path;
2767 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2768 ripped = ripped.substr (0, ripped.length() - 1);
2771 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2773 if (state_files.empty()) {
2778 this_snapshot_path = _path;
2779 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2780 this_snapshot_path += statefile_suffix;
2782 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2784 if (exclude_this_snapshot && *i == this_snapshot_path) {
2788 if (find_all_sources (*i, result) < 0) {
2796 struct RegionCounter {
2797 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2798 AudioSourceList::iterator iter;
2799 boost::shared_ptr<Region> region;
2802 RegionCounter() : count (0) {}
2806 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2808 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2809 return r.get_value_or (1);
2813 Session::cleanup_regions ()
2815 bool removed = false;
2816 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2818 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2820 uint32_t used = playlists->region_use_count (i->second);
2822 if (used == 0 && !i->second->automatic ()) {
2823 boost::weak_ptr<Region> w = i->second;
2826 RegionFactory::map_remove (w);
2833 // re-check to remove parent references of compound regions
2834 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2835 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2839 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2840 if (0 == playlists->region_use_count (i->second)) {
2841 boost::weak_ptr<Region> w = i->second;
2843 RegionFactory::map_remove (w);
2850 /* dump the history list */
2857 Session::can_cleanup_peakfiles () const
2859 if (deletion_in_progress()) {
2862 if (!_writable || (_state_of_the_state & CannotSave)) {
2863 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2866 if (record_status() == Recording) {
2867 error << _("Cannot cleanup peak-files while recording") << endmsg;
2874 Session::cleanup_peakfiles ()
2876 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2881 assert (can_cleanup_peakfiles ());
2882 assert (!peaks_cleanup_in_progres());
2884 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2886 int timeout = 5000; // 5 seconds
2887 while (!SourceFactory::files_with_peaks.empty()) {
2888 Glib::usleep (1000);
2889 if (--timeout < 0) {
2890 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2891 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2896 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2897 boost::shared_ptr<AudioSource> as;
2898 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2899 as->close_peakfile();
2903 PBD::clear_directory (session_directory().peak_path());
2905 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2907 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2908 boost::shared_ptr<AudioSource> as;
2909 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2910 SourceFactory::setup_peakfile(as, true);
2917 Session::cleanup_sources (CleanupReport& rep)
2919 // FIXME: needs adaptation to midi
2921 vector<boost::shared_ptr<Source> > dead_sources;
2924 vector<string> candidates;
2925 vector<string> unused;
2926 set<string> all_sources;
2935 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2937 /* this is mostly for windows which doesn't allow file
2938 * renaming if the file is in use. But we don't special
2939 * case it because we need to know if this causes
2940 * problems, and the easiest way to notice that is to
2941 * keep it in place for all platforms.
2944 request_stop (false);
2946 _butler->wait_until_finished ();
2948 /* consider deleting all unused playlists */
2950 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2955 /* sync the "all regions" property of each playlist with its current state
2958 playlists->sync_all_regions_with_regions ();
2960 /* find all un-used sources */
2965 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2967 SourceMap::iterator tmp;
2972 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2976 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2977 dead_sources.push_back (i->second);
2978 i->second->drop_references ();
2984 /* build a list of all the possible audio 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 asp += sdir.sound_path();
2990 audio_path += asp.to_string();
2993 /* build a list of all the possible midi directories for the session */
2995 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2996 SessionDirectory sdir ((*i).path);
2997 msp += sdir.midi_path();
2999 midi_path += msp.to_string();
3001 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3002 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3004 /* find all sources, but don't use this snapshot because the
3005 state file on disk still references sources we may have already
3009 find_all_sources_across_snapshots (all_sources, true);
3011 /* add our current source list
3014 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3015 boost::shared_ptr<FileSource> fs;
3016 SourceMap::iterator tmp = i;
3019 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3021 /* this is mostly for windows which doesn't allow file
3022 * renaming if the file is in use. But we don't special
3023 * case it because we need to know if this causes
3024 * problems, and the easiest way to notice that is to
3025 * keep it in place for all platforms.
3030 if (!fs->is_stub()) {
3032 if (playlists->source_use_count (fs) != 0) {
3033 all_sources.insert (fs->path());
3036 /* we might not remove this source from disk, because it may be used
3037 by other snapshots, but its not being used in this version
3038 so lets get rid of it now, along with any representative regions
3042 RegionFactory::remove_regions_using_source (i->second);
3044 // also remove source from all_sources
3046 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3047 spath = Glib::path_get_basename (*j);
3048 if (spath == i->second->name()) {
3049 all_sources.erase (j);
3062 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3067 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3069 tmppath1 = canonical_path (spath);
3070 tmppath2 = canonical_path ((*i));
3072 if (tmppath1 == tmppath2) {
3079 unused.push_back (spath);
3083 /* now try to move all unused files into the "dead" directory(ies) */
3085 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3090 /* don't move the file across filesystems, just
3091 stick it in the `dead_dir_name' directory
3092 on whichever filesystem it was already on.
3095 if ((*x).find ("/sounds/") != string::npos) {
3097 /* old school, go up 1 level */
3099 newpath = Glib::path_get_dirname (*x); // "sounds"
3100 newpath = Glib::path_get_dirname (newpath); // "session-name"
3104 /* new school, go up 4 levels */
3106 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3107 newpath = Glib::path_get_dirname (newpath); // "session-name"
3108 newpath = Glib::path_get_dirname (newpath); // "interchange"
3109 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3112 newpath = Glib::build_filename (newpath, dead_dir_name);
3114 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3115 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3119 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3121 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3123 /* the new path already exists, try versioning */
3125 char buf[PATH_MAX+1];
3129 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3132 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3133 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3137 if (version == 999) {
3138 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3142 newpath = newpath_v;
3147 /* it doesn't exist, or we can't read it or something */
3151 g_stat ((*x).c_str(), &statbuf);
3153 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3154 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3155 (*x), newpath, strerror (errno))
3160 /* see if there an easy to find peakfile for this file, and remove it.
3163 string base = Glib::path_get_basename (*x);
3164 base += "%A"; /* this is what we add for the channel suffix of all native files,
3165 or for the first channel of embedded files. it will miss
3166 some peakfiles for other channels
3168 string peakpath = construct_peak_filepath (base);
3170 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3171 if (::g_unlink (peakpath.c_str()) != 0) {
3172 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3173 peakpath, _path, strerror (errno))
3175 /* try to back out */
3176 ::rename (newpath.c_str(), _path.c_str());
3181 rep.paths.push_back (*x);
3182 rep.space += statbuf.st_size;
3185 /* dump the history list */
3189 /* save state so we don't end up a session file
3190 referring to non-existent sources.
3197 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3203 Session::cleanup_trash_sources (CleanupReport& rep)
3205 // FIXME: needs adaptation for MIDI
3207 vector<space_and_path>::iterator i;
3213 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3215 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3217 clear_directory (dead_dir, &rep.space, &rep.paths);
3224 Session::set_dirty ()
3226 /* never mark session dirty during loading */
3228 if (_state_of_the_state & Loading) {
3232 bool was_dirty = dirty();
3234 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3238 DirtyChanged(); /* EMIT SIGNAL */
3244 Session::set_clean ()
3246 bool was_dirty = dirty();
3248 _state_of_the_state = Clean;
3252 DirtyChanged(); /* EMIT SIGNAL */
3257 Session::set_deletion_in_progress ()
3259 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3263 Session::clear_deletion_in_progress ()
3265 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3269 Session::add_controllable (boost::shared_ptr<Controllable> c)
3271 /* this adds a controllable to the list managed by the Session.
3272 this is a subset of those managed by the Controllable class
3273 itself, and represents the only ones whose state will be saved
3274 as part of the session.
3277 Glib::Threads::Mutex::Lock lm (controllables_lock);
3278 controllables.insert (c);
3281 struct null_deleter { void operator()(void const *) const {} };
3284 Session::remove_controllable (Controllable* c)
3286 if (_state_of_the_state & Deletion) {
3290 Glib::Threads::Mutex::Lock lm (controllables_lock);
3292 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3294 if (x != controllables.end()) {
3295 controllables.erase (x);
3299 boost::shared_ptr<Controllable>
3300 Session::controllable_by_id (const PBD::ID& id)
3302 Glib::Threads::Mutex::Lock lm (controllables_lock);
3304 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3305 if ((*i)->id() == id) {
3310 return boost::shared_ptr<Controllable>();
3313 boost::shared_ptr<Controllable>
3314 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3316 boost::shared_ptr<Controllable> c;
3317 boost::shared_ptr<Route> r;
3319 switch (desc.top_level_type()) {
3320 case ControllableDescriptor::NamedRoute:
3322 std::string str = desc.top_level_name();
3323 if (str == "Master" || str == "master") {
3325 } else if (str == "control" || str == "listen") {
3328 r = route_by_name (desc.top_level_name());
3333 case ControllableDescriptor::RemoteControlID:
3334 r = route_by_remote_id (desc.rid());
3342 switch (desc.subtype()) {
3343 case ControllableDescriptor::Gain:
3344 c = r->gain_control ();
3347 case ControllableDescriptor::Trim:
3348 c = r->trim()->gain_control ();
3351 case ControllableDescriptor::Solo:
3352 c = r->solo_control();
3355 case ControllableDescriptor::Mute:
3356 c = r->mute_control();
3359 case ControllableDescriptor::Recenable:
3361 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3364 c = t->rec_enable_control ();
3369 case ControllableDescriptor::PanDirection:
3371 c = r->pannable()->pan_azimuth_control;
3375 case ControllableDescriptor::PanWidth:
3377 c = r->pannable()->pan_width_control;
3381 case ControllableDescriptor::PanElevation:
3383 c = r->pannable()->pan_elevation_control;
3387 case ControllableDescriptor::Balance:
3388 /* XXX simple pan control */
3391 case ControllableDescriptor::PluginParameter:
3393 uint32_t plugin = desc.target (0);
3394 uint32_t parameter_index = desc.target (1);
3396 /* revert to zero based counting */
3402 if (parameter_index > 0) {
3406 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3409 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3410 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3415 case ControllableDescriptor::SendGain:
3417 uint32_t send = desc.target (0);
3419 /* revert to zero-based counting */
3425 boost::shared_ptr<Processor> p = r->nth_send (send);
3428 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3429 boost::shared_ptr<Amp> a = s->amp();
3432 c = s->amp()->gain_control();
3439 /* relax and return a null pointer */
3447 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3450 Stateful::add_instant_xml (node, _path);
3453 if (write_to_config) {
3454 Config->add_instant_xml (node);
3459 Session::instant_xml (const string& node_name)
3461 return Stateful::instant_xml (node_name, _path);
3465 Session::save_history (string snapshot_name)
3473 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3474 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3478 if (snapshot_name.empty()) {
3479 snapshot_name = _current_snapshot_name;
3482 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3483 const string backup_filename = history_filename + backup_suffix;
3484 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3485 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3487 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3488 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3489 error << _("could not backup old history file, current history not saved") << endmsg;
3494 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3496 if (!tree.write (xml_path))
3498 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3500 if (g_remove (xml_path.c_str()) != 0) {
3501 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3502 xml_path, g_strerror (errno)) << endmsg;
3504 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3505 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3506 backup_path, g_strerror (errno)) << endmsg;
3516 Session::restore_history (string snapshot_name)
3520 if (snapshot_name.empty()) {
3521 snapshot_name = _current_snapshot_name;
3524 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3525 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3527 info << "Loading history from " << xml_path << endmsg;
3529 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3530 info << string_compose (_("%1: no history file \"%2\" for this session."),
3531 _name, xml_path) << endmsg;
3535 if (!tree.read (xml_path)) {
3536 error << string_compose (_("Could not understand session history file \"%1\""),
3537 xml_path) << endmsg;
3544 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3547 UndoTransaction* ut = new UndoTransaction ();
3550 ut->set_name(t->property("name")->value());
3551 stringstream ss(t->property("tv-sec")->value());
3553 ss.str(t->property("tv-usec")->value());
3555 ut->set_timestamp(tv);
3557 for (XMLNodeConstIterator child_it = t->children().begin();
3558 child_it != t->children().end(); child_it++)
3560 XMLNode *n = *child_it;
3563 if (n->name() == "MementoCommand" ||
3564 n->name() == "MementoUndoCommand" ||
3565 n->name() == "MementoRedoCommand") {
3567 if ((c = memento_command_factory(n))) {
3571 } else if (n->name() == "NoteDiffCommand") {
3572 PBD::ID id (n->property("midi-source")->value());
3573 boost::shared_ptr<MidiSource> midi_source =
3574 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3576 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3578 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3581 } else if (n->name() == "SysExDiffCommand") {
3583 PBD::ID id (n->property("midi-source")->value());
3584 boost::shared_ptr<MidiSource> midi_source =
3585 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3587 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3589 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3592 } else if (n->name() == "PatchChangeDiffCommand") {
3594 PBD::ID id (n->property("midi-source")->value());
3595 boost::shared_ptr<MidiSource> midi_source =
3596 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3598 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3600 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3603 } else if (n->name() == "StatefulDiffCommand") {
3604 if ((c = stateful_diff_command_factory (n))) {
3605 ut->add_command (c);
3608 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3619 Session::config_changed (std::string p, bool ours)
3625 if (p == "seamless-loop") {
3627 } else if (p == "rf-speed") {
3629 } else if (p == "auto-loop") {
3631 } else if (p == "auto-input") {
3633 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3634 /* auto-input only makes a difference if we're rolling */
3635 set_track_monitor_input_status (!config.get_auto_input());
3638 } else if (p == "punch-in") {
3642 if ((location = _locations->auto_punch_location()) != 0) {
3644 if (config.get_punch_in ()) {
3645 replace_event (SessionEvent::PunchIn, location->start());
3647 remove_event (location->start(), SessionEvent::PunchIn);
3651 } else if (p == "punch-out") {
3655 if ((location = _locations->auto_punch_location()) != 0) {
3657 if (config.get_punch_out()) {
3658 replace_event (SessionEvent::PunchOut, location->end());
3660 clear_events (SessionEvent::PunchOut);
3664 } else if (p == "edit-mode") {
3666 Glib::Threads::Mutex::Lock lm (playlists->lock);
3668 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3669 (*i)->set_edit_mode (Config->get_edit_mode ());
3672 } else if (p == "use-video-sync") {
3674 waiting_for_sync_offset = config.get_use_video_sync();
3676 } else if (p == "mmc-control") {
3678 //poke_midi_thread ();
3680 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3682 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3684 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3686 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3688 } else if (p == "midi-control") {
3690 //poke_midi_thread ();
3692 } else if (p == "raid-path") {
3694 setup_raid_path (config.get_raid_path());
3696 } else if (p == "timecode-format") {
3700 } else if (p == "video-pullup") {
3704 } else if (p == "seamless-loop") {
3706 if (play_loop && transport_rolling()) {
3707 // to reset diskstreams etc
3708 request_play_loop (true);
3711 } else if (p == "rf-speed") {
3713 cumulative_rf_motion = 0;
3716 } else if (p == "click-sound") {
3718 setup_click_sounds (1);
3720 } else if (p == "click-emphasis-sound") {
3722 setup_click_sounds (-1);
3724 } else if (p == "clicking") {
3726 if (Config->get_clicking()) {
3727 if (_click_io && click_data) { // don't require emphasis data
3734 } else if (p == "click-gain") {
3737 _click_gain->set_gain (Config->get_click_gain(), this);
3740 } else if (p == "send-mtc") {
3742 if (Config->get_send_mtc ()) {
3743 /* mark us ready to send */
3744 next_quarter_frame_to_send = 0;
3747 } else if (p == "send-mmc") {
3749 _mmc->enable_send (Config->get_send_mmc ());
3751 } else if (p == "midi-feedback") {
3753 session_midi_feedback = Config->get_midi_feedback();
3755 } else if (p == "jack-time-master") {
3757 engine().reset_timebase ();
3759 } else if (p == "native-file-header-format") {
3761 if (!first_file_header_format_reset) {
3762 reset_native_file_format ();
3765 first_file_header_format_reset = false;
3767 } else if (p == "native-file-data-format") {
3769 if (!first_file_data_format_reset) {
3770 reset_native_file_format ();
3773 first_file_data_format_reset = false;
3775 } else if (p == "external-sync") {
3776 if (!config.get_external_sync()) {
3777 drop_sync_source ();
3779 switch_to_sync_source (Config->get_sync_source());
3781 } else if (p == "denormal-model") {
3783 } else if (p == "history-depth") {
3784 set_history_depth (Config->get_history_depth());
3785 } else if (p == "remote-model") {
3786 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3789 } else if (p == "initial-program-change") {
3791 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3794 buf[0] = MIDI::program; // channel zero by default
3795 buf[1] = (Config->get_initial_program_change() & 0x7f);
3797 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3799 } else if (p == "solo-mute-override") {
3800 // catch_up_on_solo_mute_override ();
3801 } else if (p == "listen-position" || p == "pfl-position") {
3802 listen_position_changed ();
3803 } else if (p == "solo-control-is-listen-control") {
3804 solo_control_mode_changed ();
3805 } else if (p == "solo-mute-gain") {
3806 _solo_cut_control->Changed();
3807 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3808 last_timecode_valid = false;
3809 } else if (p == "playback-buffer-seconds") {
3810 AudioSource::allocate_working_buffers (frame_rate());
3811 } else if (p == "ltc-source-port") {
3812 reconnect_ltc_input ();
3813 } else if (p == "ltc-sink-port") {
3814 reconnect_ltc_output ();
3815 } else if (p == "timecode-generator-offset") {
3816 ltc_tx_parse_offset();
3817 } else if (p == "auto-return-target-list") {
3818 follow_playhead_priority ();
3825 Session::set_history_depth (uint32_t d)
3827 _history.set_depth (d);
3831 Session::load_diskstreams_2X (XMLNode const & node, int)
3834 XMLNodeConstIterator citer;
3836 clist = node.children();
3838 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3841 /* diskstreams added automatically by DiskstreamCreated handler */
3842 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3843 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3844 _diskstreams_2X.push_back (dsp);
3846 error << _("Session: unknown diskstream type in XML") << endmsg;
3850 catch (failed_constructor& err) {
3851 error << _("Session: could not load diskstream via XML state") << endmsg;
3859 /** Connect things to the MMC object */
3861 Session::setup_midi_machine_control ()
3863 _mmc = new MIDI::MachineControl;
3864 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3866 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3867 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3868 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3869 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3870 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3871 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3872 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3873 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3874 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3875 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3876 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3877 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3878 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3880 /* also handle MIDI SPP because its so common */
3882 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3883 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3884 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3887 boost::shared_ptr<Controllable>
3888 Session::solo_cut_control() const
3890 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3891 controls in Ardour that currently get presented to the user in the GUI that require
3892 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3894 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3895 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3899 return _solo_cut_control;
3903 Session::rename (const std::string& new_name)
3905 string legal_name = legalize_for_path (new_name);
3911 string const old_sources_root = _session_dir->sources_root();
3913 if (!_writable || (_state_of_the_state & CannotSave)) {
3914 error << _("Cannot rename read-only session.") << endmsg;
3915 return 0; // don't show "messed up" warning
3917 if (record_status() == Recording) {
3918 error << _("Cannot rename session while recording") << endmsg;
3919 return 0; // don't show "messed up" warning
3922 StateProtector stp (this);
3927 * interchange subdirectory
3931 * Backup files are left unchanged and not renamed.
3934 /* Windows requires that we close all files before attempting the
3935 * rename. This works on other platforms, but isn't necessary there.
3936 * Leave it in place for all platforms though, since it may help
3937 * catch issues that could arise if the way Source files work ever
3938 * change (since most developers are not using Windows).
3941 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3942 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3948 /* pass one: not 100% safe check that the new directory names don't
3952 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3956 /* this is a stupid hack because Glib::path_get_dirname() is
3957 * lexical-only, and so passing it /a/b/c/ gives a different
3958 * result than passing it /a/b/c ...
3961 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3962 oldstr = oldstr.substr (0, oldstr.length() - 1);
3965 string base = Glib::path_get_dirname (oldstr);
3967 newstr = Glib::build_filename (base, legal_name);
3969 cerr << "Looking for " << newstr << endl;
3971 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3972 cerr << " exists\n";
3981 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3987 /* this is a stupid hack because Glib::path_get_dirname() is
3988 * lexical-only, and so passing it /a/b/c/ gives a different
3989 * result than passing it /a/b/c ...
3992 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3993 oldstr = oldstr.substr (0, oldstr.length() - 1);
3996 string base = Glib::path_get_dirname (oldstr);
3997 newstr = Glib::build_filename (base, legal_name);
3999 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4001 cerr << "Rename " << oldstr << " => " << newstr << endl;
4002 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4003 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4004 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4008 /* Reset path in "session dirs" */
4013 /* reset primary SessionDirectory object */
4016 (*_session_dir) = newstr;
4021 /* now rename directory below session_dir/interchange */
4023 string old_interchange_dir;
4024 string new_interchange_dir;
4026 /* use newstr here because we renamed the path
4027 * (folder/directory) that used to be oldstr to newstr above
4030 v.push_back (newstr);
4031 v.push_back (interchange_dir_name);
4032 v.push_back (Glib::path_get_basename (oldstr));
4034 old_interchange_dir = Glib::build_filename (v);
4037 v.push_back (newstr);
4038 v.push_back (interchange_dir_name);
4039 v.push_back (legal_name);
4041 new_interchange_dir = Glib::build_filename (v);
4043 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4045 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4046 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4047 old_interchange_dir, new_interchange_dir,
4050 error << string_compose (_("renaming %s as %2 failed (%3)"),
4051 old_interchange_dir, new_interchange_dir,
4060 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4061 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4063 cerr << "Rename " << oldstr << " => " << newstr << endl;
4065 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4066 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4067 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4073 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4075 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4076 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4078 cerr << "Rename " << oldstr << " => " << newstr << endl;
4080 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4081 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4082 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4087 /* remove old name from recent sessions */
4088 remove_recent_sessions (_path);
4091 /* update file source paths */
4093 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4094 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4096 string p = fs->path ();
4097 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4099 SourceFactory::setup_peakfile(i->second, true);
4103 _current_snapshot_name = new_name;
4108 /* save state again to get everything just right */
4110 save_state (_current_snapshot_name);
4112 /* add to recent sessions */
4114 store_recent_sessions (new_name, _path);
4120 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4122 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4126 if (!tree.read (xmlpath)) {
4134 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4137 bool found_sr = false;
4138 bool found_data_format = false;
4140 if (get_session_info_from_path (tree, xmlpath)) {
4146 const XMLProperty* prop;
4147 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
4148 sample_rate = atoi (prop->value());
4152 const XMLNodeList& children (tree.root()->children());
4153 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4154 const XMLNode* child = *c;
4155 if (child->name() == "Config") {
4156 const XMLNodeList& options (child->children());
4157 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4158 const XMLNode* option = *oc;
4159 const XMLProperty* name = option->property("name");
4165 if (name->value() == "native-file-data-format") {
4166 const XMLProperty* value = option->property ("value");
4168 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4170 found_data_format = true;
4176 if (found_data_format) {
4181 return !(found_sr && found_data_format); // zero if they are both found
4184 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4185 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4188 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4192 SourcePathMap source_path_map;
4194 boost::shared_ptr<AudioFileSource> afs;
4199 Glib::Threads::Mutex::Lock lm (source_lock);
4201 cerr << " total sources = " << sources.size();
4203 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4204 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4210 if (fs->within_session()) {
4214 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4215 source_path_map[fs->path()].push_back (fs);
4217 SeveralFileSources v;
4219 source_path_map.insert (make_pair (fs->path(), v));
4225 cerr << " fsources = " << total << endl;
4227 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4229 /* tell caller where we are */
4231 string old_path = i->first;
4233 callback (n, total, old_path);
4235 cerr << old_path << endl;
4239 switch (i->second.front()->type()) {
4240 case DataType::AUDIO:
4241 new_path = new_audio_source_path_for_embedded (old_path);
4244 case DataType::MIDI:
4245 /* XXX not implemented yet */
4249 if (new_path.empty()) {
4253 cerr << "Move " << old_path << " => " << new_path << endl;
4255 if (!copy_file (old_path, new_path)) {
4256 cerr << "failed !\n";
4260 /* make sure we stop looking in the external
4261 dir/folder. Remember, this is an all-or-nothing
4262 operations, it doesn't merge just some files.
4264 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4266 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4267 (*f)->set_path (new_path);
4272 save_state ("", false, false);
4278 bool accept_all_files (string const &, void *)
4284 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4286 /* 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.
4291 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4293 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4295 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4297 v.push_back (new_session_folder); /* full path */
4298 v.push_back (interchange_dir_name);
4299 v.push_back (new_session_path); /* just one directory/folder */
4300 v.push_back (typedir);
4301 v.push_back (Glib::path_get_basename (old_path));
4303 return Glib::build_filename (v);
4307 Session::save_as (SaveAs& saveas)
4309 vector<string> files;
4310 string current_folder = Glib::path_get_dirname (_path);
4311 string new_folder = legalize_for_path (saveas.new_name);
4312 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4313 int64_t total_bytes = 0;
4317 int32_t internal_file_cnt = 0;
4319 vector<string> do_not_copy_extensions;
4320 do_not_copy_extensions.push_back (statefile_suffix);
4321 do_not_copy_extensions.push_back (pending_suffix);
4322 do_not_copy_extensions.push_back (backup_suffix);
4323 do_not_copy_extensions.push_back (temp_suffix);
4324 do_not_copy_extensions.push_back (history_suffix);
4326 /* get total size */
4328 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4330 /* need to clear this because
4331 * find_files_matching_filter() is cumulative
4336 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4338 all += files.size();
4340 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4342 g_stat ((*i).c_str(), &gsb);
4343 total_bytes += gsb.st_size;
4347 /* save old values so we can switch back if we are not switching to the new session */
4349 string old_path = _path;
4350 string old_name = _name;
4351 string old_snapshot = _current_snapshot_name;
4352 string old_sd = _session_dir->root_path();
4353 vector<string> old_search_path[DataType::num_types];
4354 string old_config_search_path[DataType::num_types];
4356 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4357 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4358 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4359 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4361 /* switch session directory */
4363 (*_session_dir) = to_dir;
4365 /* create new tree */
4367 if (!_session_dir->create()) {
4368 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4373 /* copy all relevant files. Find each location in session_dirs,
4374 * and copy files from there to target.
4377 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4379 /* need to clear this because
4380 * find_files_matching_filter() is cumulative
4385 const size_t prefix_len = (*sd).path.size();
4387 /* Work just on the files within this session dir */
4389 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4391 /* add dir separator to protect against collisions with
4392 * track names (e.g. track named "audiofiles" or
4396 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4397 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4398 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4400 /* copy all the files. Handling is different for media files
4401 than others because of the *silly* subtree we have below the interchange
4402 folder. That really was a bad idea, but I'm not fixing it as part of
4403 implementing ::save_as().
4406 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4408 std::string from = *i;
4411 string filename = Glib::path_get_basename (from);
4412 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4413 if (filename == ".DS_STORE") {
4418 if (from.find (audiofile_dir_string) != string::npos) {
4420 /* audio file: only copy if asked */
4422 if (saveas.include_media && saveas.copy_media) {
4424 string to = make_new_media_path (*i, to_dir, new_folder);
4426 info << "media file copying from " << from << " to " << to << endmsg;
4428 if (!copy_file (from, to)) {
4429 throw Glib::FileError (Glib::FileError::IO_ERROR,
4430 string_compose(_("\ncopying \"%1\" failed !"), from));
4434 /* we found media files inside the session folder */
4436 internal_file_cnt++;
4438 } else if (from.find (midifile_dir_string) != string::npos) {
4440 /* midi file: always copy unless
4441 * creating an empty new session
4444 if (saveas.include_media) {
4446 string to = make_new_media_path (*i, to_dir, new_folder);
4448 info << "media file copying from " << from << " to " << to << endmsg;
4450 if (!copy_file (from, to)) {
4451 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4455 /* we found media files inside the session folder */
4457 internal_file_cnt++;
4459 } else if (from.find (analysis_dir_string) != string::npos) {
4461 /* make sure analysis dir exists in
4462 * new session folder, but we're not
4463 * copying analysis files here, see
4467 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4472 /* normal non-media file. Don't copy state, history, etc.
4475 bool do_copy = true;
4477 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4478 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4479 /* end of filename matches extension, do not copy file */
4485 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4486 /* don't copy peakfiles if
4487 * we're not copying media
4493 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4495 info << "attempting to make directory/folder " << to << endmsg;
4497 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4498 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4501 info << "attempting to copy " << from << " to " << to << endmsg;
4503 if (!copy_file (from, to)) {
4504 throw Glib::FileError (Glib::FileError::IO_ERROR,
4505 string_compose(_("\ncopying \"%1\" failed !"), from));
4510 /* measure file size even if we're not going to copy so that our Progress
4511 signals are correct, since we included these do-not-copy files
4512 in the computation of the total size and file count.
4516 g_stat (from.c_str(), &gsb);
4517 copied += gsb.st_size;
4520 double fraction = (double) copied / total_bytes;
4522 bool keep_going = true;
4524 if (saveas.copy_media) {
4526 /* no need or expectation of this if
4527 * media is not being copied, because
4528 * it will be fast(ish).
4531 /* tell someone "X percent, file M of N"; M is one-based */
4533 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4541 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4547 /* copy optional folders, if any */
4549 string old = plugins_dir ();
4550 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4551 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4552 copy_files (old, newdir);
4555 old = externals_dir ();
4556 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4557 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4558 copy_files (old, newdir);
4561 old = automation_dir ();
4562 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4563 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4564 copy_files (old, newdir);
4567 if (saveas.include_media) {
4569 if (saveas.copy_media) {
4570 #ifndef PLATFORM_WINDOWS
4571 /* There are problems with analysis files on
4572 * Windows, because they used a colon in their
4573 * names as late as 4.0. Colons are not legal
4574 * under Windows even if NTFS allows them.
4576 * This is a tricky problem to solve so for
4577 * just don't copy these files. They will be
4578 * regenerated as-needed anyway, subject to the
4579 * existing issue that the filenames will be
4580 * rejected by Windows, which is a separate
4581 * problem (though related).
4584 /* only needed if we are copying media, since the
4585 * analysis data refers to media data
4588 old = analysis_dir ();
4589 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4590 string newdir = Glib::build_filename (to_dir, "analysis");
4591 copy_files (old, newdir);
4593 #endif /* PLATFORM_WINDOWS */
4599 _current_snapshot_name = saveas.new_name;
4600 _name = saveas.new_name;
4602 if (saveas.include_media && !saveas.copy_media) {
4604 /* reset search paths of the new session (which we're pretending to be right now) to
4605 include the original session search path, so we can still find all audio.
4608 if (internal_file_cnt) {
4609 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4610 ensure_search_path_includes (*s, DataType::AUDIO);
4611 cerr << "be sure to include " << *s << " for audio" << endl;
4614 /* we do not do this for MIDI because we copy
4615 all MIDI files if saveas.include_media is
4621 bool was_dirty = dirty ();
4623 save_state ("", false, false, !saveas.include_media);
4624 save_default_options ();
4626 if (saveas.copy_media && saveas.copy_external) {
4627 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4628 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4632 saveas.final_session_folder_name = _path;
4634 store_recent_sessions (_name, _path);
4636 if (!saveas.switch_to) {
4638 /* switch back to the way things were */
4642 _current_snapshot_name = old_snapshot;
4644 (*_session_dir) = old_sd;
4650 if (internal_file_cnt) {
4651 /* reset these to their original values */
4652 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4653 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4658 /* prune session dirs, and update disk space statistics
4663 session_dirs.clear ();
4664 session_dirs.push_back (sp);
4665 refresh_disk_space ();
4667 /* ensure that all existing tracks reset their current capture source paths
4669 reset_write_sources (true, true);
4671 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4672 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4675 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4676 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4682 if (fs->within_session()) {
4683 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4684 fs->set_path (newpath);
4689 } catch (Glib::FileError& e) {
4691 saveas.failure_message = e.what();
4693 /* recursively remove all the directories */
4695 remove_directory (to_dir);
4703 saveas.failure_message = _("unknown reason");
4705 /* recursively remove all the directories */
4707 remove_directory (to_dir);