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/basename.h"
65 #include "pbd/controllable_descriptor.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_utils.h"
70 #include "pbd/pathexpand.h"
71 #include "pbd/pthread_utils.h"
72 #include "pbd/stacktrace.h"
73 #include "pbd/convert.h"
74 #include "pbd/localtime_r.h"
75 #include "pbd/unwind.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/boost_debug.h"
86 #include "ardour/butler.h"
87 #include "ardour/control_protocol_manager.h"
88 #include "ardour/directory_names.h"
89 #include "ardour/filename_extensions.h"
90 #include "ardour/graph.h"
91 #include "ardour/location.h"
92 #include "ardour/midi_model.h"
93 #include "ardour/midi_patch_manager.h"
94 #include "ardour/midi_region.h"
95 #include "ardour/midi_scene_changer.h"
96 #include "ardour/midi_source.h"
97 #include "ardour/midi_track.h"
98 #include "ardour/pannable.h"
99 #include "ardour/playlist_factory.h"
100 #include "ardour/playlist_source.h"
101 #include "ardour/port.h"
102 #include "ardour/processor.h"
103 #include "ardour/profile.h"
104 #include "ardour/proxy_controllable.h"
105 #include "ardour/recent_sessions.h"
106 #include "ardour/region_factory.h"
107 #include "ardour/route_group.h"
108 #include "ardour/send.h"
109 #include "ardour/session.h"
110 #include "ardour/session_directory.h"
111 #include "ardour/session_metadata.h"
112 #include "ardour/session_playlists.h"
113 #include "ardour/session_state_utils.h"
114 #include "ardour/silentfilesource.h"
115 #include "ardour/sndfilesource.h"
116 #include "ardour/source_factory.h"
117 #include "ardour/speakers.h"
118 #include "ardour/template_utils.h"
119 #include "ardour/tempo.h"
120 #include "ardour/ticker.h"
121 #include "ardour/user_bundle.h"
122 #include "ardour/vca_manager.h"
124 #include "control_protocol/control_protocol.h"
126 #include "LuaBridge/LuaBridge.h"
132 using namespace ARDOUR;
135 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
138 Session::pre_engine_init (string fullpath)
140 if (fullpath.empty()) {
142 throw failed_constructor();
145 /* discover canonical fullpath */
147 _path = canonical_path(fullpath);
150 if (Profile->get_trx() ) {
151 // Waves TracksLive has a usecase of session replacement with a new one.
152 // We should check session state file (<session_name>.ardour) existance
153 // to determine if the session is new or not
155 string full_session_name = Glib::build_filename( fullpath, _name );
156 full_session_name += statefile_suffix;
158 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
160 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
163 /* finish initialization that can't be done in a normal C++ constructor
167 timerclear (&last_mmc_step);
168 g_atomic_int_set (&processing_prohibited, 0);
169 g_atomic_int_set (&_record_status, Disabled);
170 g_atomic_int_set (&_playback_load, 100);
171 g_atomic_int_set (&_capture_load, 100);
173 _all_route_group->set_active (true, this);
174 interpolation.add_channel_to (0, 0);
175 _vca_manager = new VCAManager (*this);
177 if (config.get_use_video_sync()) {
178 waiting_for_sync_offset = true;
180 waiting_for_sync_offset = false;
183 last_rr_session_dir = session_dirs.begin();
185 set_history_depth (Config->get_history_depth());
187 /* default: assume simple stereo speaker configuration */
189 _speakers->setup_default_speakers (2);
191 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
192 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
193 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
194 add_controllable (_solo_cut_control);
196 /* These are all static "per-class" signals */
198 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
199 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
200 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
201 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
202 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
204 /* stop IO objects from doing stuff until we're ready for them */
206 Delivery::disable_panners ();
207 IO::disable_connecting ();
211 Session::post_engine_init ()
213 BootMessage (_("Set block size and sample rate"));
215 set_block_size (_engine.samples_per_cycle());
216 set_frame_rate (_engine.sample_rate());
218 BootMessage (_("Using configuration"));
220 _midi_ports = new MidiPortManager;
222 MIDISceneChanger* msc;
224 _scene_changer = msc = new MIDISceneChanger (*this);
225 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
226 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
228 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
229 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
231 setup_midi_machine_control ();
233 if (_butler->start_thread()) {
237 if (start_midi_thread ()) {
241 setup_click_sounds (0);
242 setup_midi_control ();
244 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
245 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
248 /* tempo map requires sample rate knowledge */
251 _tempo_map = new TempoMap (_current_frame_rate);
252 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
253 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::gui_tempo_map_changed, this));
255 /* MidiClock requires a tempo map */
258 midi_clock = new MidiClockTicker ();
259 midi_clock->set_session (this);
261 /* crossfades require sample rate knowledge */
263 SndFileSource::setup_standard_crossfades (*this, frame_rate());
264 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
266 AudioDiskstream::allocate_working_buffers();
267 refresh_disk_space ();
269 /* we're finally ready to call set_state() ... all objects have
270 * been created, the engine is running.
274 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
278 // set_state() will call setup_raid_path(), but if it's a new session we need
279 // to call setup_raid_path() here.
280 setup_raid_path (_path);
285 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
286 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
288 Config->map_parameters (ff);
289 config.map_parameters (ft);
290 _butler->map_parameters ();
292 /* Reset all panners */
294 Delivery::reset_panners ();
296 /* this will cause the CPM to instantiate any protocols that are in use
297 * (or mandatory), which will pass it this Session, and then call
298 * set_state() on each instantiated protocol to match stored state.
301 ControlProtocolManager::instance().set_session (this);
303 /* This must be done after the ControlProtocolManager set_session above,
304 as it will set states for ports which the ControlProtocolManager creates.
307 // XXX set state of MIDI::Port's
308 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
310 /* And this must be done after the MIDI::Manager::set_port_states as
311 * it will try to make connections whose details are loaded by set_port_states.
316 /* Let control protocols know that we are now all connected, so they
317 * could start talking to surfaces if they want to.
320 ControlProtocolManager::instance().midi_connectivity_established ();
322 if (_is_new && !no_auto_connect()) {
323 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
324 auto_connect_master_bus ();
327 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
329 /* update latencies */
331 initialize_latencies ();
333 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
334 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
335 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
337 } catch (AudioEngine::PortRegistrationFailure& err) {
338 /* handle this one in a different way than all others, so that its clear what happened */
339 error << err.what() << endmsg;
345 BootMessage (_("Reset Remote Controls"));
347 // send_full_time_code (0);
348 _engine.transport_locate (0);
350 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
351 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
353 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
356 /* initial program change will be delivered later; see ::config_changed() */
358 _state_of_the_state = Clean;
360 Port::set_connecting_blocked (false);
362 DirtyChanged (); /* EMIT SIGNAL */
366 } else if (state_was_pending) {
368 remove_pending_capture_state ();
369 state_was_pending = false;
372 /* Now, finally, we can fill the playback buffers */
374 BootMessage (_("Filling playback buffers"));
376 boost::shared_ptr<RouteList> rl = routes.reader();
377 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
378 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
379 if (trk && !trk->hidden()) {
380 trk->seek (_transport_frame, true);
388 Session::session_loaded ()
392 _state_of_the_state = Clean;
394 DirtyChanged (); /* EMIT SIGNAL */
398 } else if (state_was_pending) {
400 remove_pending_capture_state ();
401 state_was_pending = false;
404 /* Now, finally, we can fill the playback buffers */
406 BootMessage (_("Filling playback buffers"));
407 force_locate (_transport_frame, false);
411 Session::raid_path () const
413 Searchpath raid_search_path;
415 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
416 raid_search_path += (*i).path;
419 return raid_search_path.to_string ();
423 Session::setup_raid_path (string path)
432 session_dirs.clear ();
434 Searchpath search_path(path);
435 Searchpath sound_search_path;
436 Searchpath midi_search_path;
438 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
440 sp.blocks = 0; // not needed
441 session_dirs.push_back (sp);
443 SessionDirectory sdir(sp.path);
445 sound_search_path += sdir.sound_path ();
446 midi_search_path += sdir.midi_path ();
449 // reset the round-robin soundfile path thingie
450 last_rr_session_dir = session_dirs.begin();
454 Session::path_is_within_session (const std::string& path)
456 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
457 if (PBD::path_is_within (i->path, path)) {
465 Session::ensure_subdirs ()
469 dir = session_directory().peak_path();
471 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
472 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
476 dir = session_directory().sound_path();
478 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
479 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
483 dir = session_directory().midi_path();
485 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
486 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
490 dir = session_directory().dead_path();
492 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
493 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
497 dir = session_directory().export_path();
499 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
500 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
504 dir = analysis_dir ();
506 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
507 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
511 dir = plugins_dir ();
513 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
514 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
518 dir = externals_dir ();
520 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
521 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
528 /** @param session_template directory containing session template, or empty.
529 * Caller must not hold process lock.
532 Session::create (const string& session_template, BusProfile* bus_profile)
534 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
535 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
539 if (ensure_subdirs ()) {
543 _writable = exists_and_writable (_path);
545 if (!session_template.empty()) {
546 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
548 FILE* in = g_fopen (in_path.c_str(), "rb");
551 /* no need to call legalize_for_path() since the string
552 * in session_template is already a legal path name
554 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
556 FILE* out = g_fopen (out_path.c_str(), "wb");
560 stringstream new_session;
563 size_t charsRead = fread (buf, sizeof(char), 1024, in);
566 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
571 if (charsRead == 0) {
574 new_session.write (buf, charsRead);
578 string file_contents = new_session.str();
579 size_t writeSize = file_contents.length();
580 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
581 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
589 if (!ARDOUR::Profile->get_trx()) {
590 /* Copy plugin state files from template to new session */
591 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
592 copy_recurse (template_plugins, plugins_dir ());
598 error << string_compose (_("Could not open %1 for writing session template"), out_path)
605 error << string_compose (_("Could not open session template %1 for reading"), in_path)
612 if (Profile->get_trx()) {
614 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
615 Remember that this is a brand new session. Sessions
616 loaded from saved state will get this range from the saved state.
619 set_session_range_location (0, 0);
621 /* Initial loop location, from absolute zero, length 10 seconds */
623 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
624 _locations->add (loc, true);
625 set_auto_loop_location (loc);
628 _state_of_the_state = Clean;
630 /* set up Master Out and Control Out if necessary */
635 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
637 // Waves Tracks: always create master bus for Tracks
638 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
639 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
647 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
648 r->input()->ensure_io (count, false, this);
649 r->output()->ensure_io (count, false, this);
655 /* prohibit auto-connect to master, because there isn't one */
656 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
660 add_routes (rl, false, false, false);
663 // Waves Tracks: Skip this. Always use autoconnection for Tracks
664 if (!ARDOUR::Profile->get_trx()) {
666 /* this allows the user to override settings with an environment variable.
669 if (no_auto_connect()) {
670 bus_profile->input_ac = AutoConnectOption (0);
671 bus_profile->output_ac = AutoConnectOption (0);
674 Config->set_input_auto_connect (bus_profile->input_ac);
675 Config->set_output_auto_connect (bus_profile->output_ac);
679 if (Config->get_use_monitor_bus() && bus_profile) {
680 add_monitor_section ();
687 Session::maybe_write_autosave()
689 if (dirty() && record_status() != Recording) {
690 save_state("", true);
695 Session::remove_pending_capture_state ()
697 std::string pending_state_file_path(_session_dir->root_path());
699 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
701 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
703 if (g_remove (pending_state_file_path.c_str()) != 0) {
704 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
705 pending_state_file_path, g_strerror (errno)) << endmsg;
709 /** Rename a state file.
710 * @param old_name Old snapshot name.
711 * @param new_name New snapshot name.
714 Session::rename_state (string old_name, string new_name)
716 if (old_name == _current_snapshot_name || old_name == _name) {
717 /* refuse to rename the current snapshot or the "main" one */
721 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
722 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
724 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
725 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
727 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
728 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
729 old_name, new_name, g_strerror(errno)) << endmsg;
733 /** Remove a state file.
734 * @param snapshot_name Snapshot name.
737 Session::remove_state (string snapshot_name)
739 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
740 // refuse to remove the current snapshot or the "main" one
744 std::string xml_path(_session_dir->root_path());
746 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
748 if (!create_backup_file (xml_path)) {
749 // don't remove it if a backup can't be made
750 // create_backup_file will log the error.
755 if (g_remove (xml_path.c_str()) != 0) {
756 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
757 xml_path, g_strerror (errno)) << endmsg;
761 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
763 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
765 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
768 std::string xml_path(_session_dir->root_path());
770 /* prevent concurrent saves from different threads */
772 Glib::Threads::Mutex::Lock lm (save_state_lock);
774 if (!_writable || (_state_of_the_state & CannotSave)) {
778 if (g_atomic_int_get(&_suspend_save)) {
782 _save_queued = false;
784 if (!_engine.connected ()) {
785 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
792 const int64_t save_start_time = g_get_monotonic_time();
795 /* tell sources we're saving first, in case they write out to a new file
796 * which should be saved with the state rather than the old one */
797 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
799 i->second->session_saved();
800 } catch (Evoral::SMF::FileError& e) {
801 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
805 SessionSaveUnderway (); /* EMIT SIGNAL */
807 bool mark_as_clean = true;
809 if (!snapshot_name.empty() && !switch_to_snapshot) {
810 mark_as_clean = false;
814 mark_as_clean = false;
815 tree.set_root (&get_template());
817 tree.set_root (&get_state());
820 if (snapshot_name.empty()) {
821 snapshot_name = _current_snapshot_name;
822 } else if (switch_to_snapshot) {
823 set_snapshot_name (snapshot_name);
826 assert (!snapshot_name.empty());
830 /* proper save: use statefile_suffix (.ardour in English) */
832 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
834 /* make a backup copy of the old file */
836 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
837 // create_backup_file will log the error
843 /* pending save: use pending_suffix (.pending in English) */
844 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
847 std::string tmp_path(_session_dir->root_path());
848 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
850 cerr << "actually writing state to " << tmp_path << endl;
852 if (!tree.write (tmp_path)) {
853 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
854 if (g_remove (tmp_path.c_str()) != 0) {
855 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
856 tmp_path, g_strerror (errno)) << endmsg;
862 cerr << "renaming state to " << xml_path << endl;
864 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
865 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
866 tmp_path, xml_path, g_strerror(errno)) << endmsg;
867 if (g_remove (tmp_path.c_str()) != 0) {
868 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
869 tmp_path, g_strerror (errno)) << endmsg;
877 save_history (snapshot_name);
880 bool was_dirty = dirty();
882 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
885 DirtyChanged (); /* EMIT SIGNAL */
889 StateSaved (snapshot_name); /* EMIT SIGNAL */
893 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
894 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
900 Session::restore_state (string snapshot_name)
902 if (load_state (snapshot_name) == 0) {
903 set_state (*state_tree->root(), Stateful::loading_state_version);
910 Session::load_state (string snapshot_name)
915 state_was_pending = false;
917 /* check for leftover pending state from a crashed capture attempt */
919 std::string xmlpath(_session_dir->root_path());
920 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
922 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
924 /* there is pending state from a crashed capture attempt */
926 boost::optional<int> r = AskAboutPendingState();
927 if (r.get_value_or (1)) {
928 state_was_pending = true;
932 if (!state_was_pending) {
933 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
936 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
937 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
938 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
939 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
944 state_tree = new XMLTree;
948 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
950 if (!state_tree->read (xmlpath)) {
951 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
957 XMLNode const & root (*state_tree->root());
959 if (root.name() != X_("Session")) {
960 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
966 XMLProperty const * prop;
968 if ((prop = root.property ("version")) == 0) {
969 /* no version implies very old version of Ardour */
970 Stateful::loading_state_version = 1000;
972 if (prop->value().find ('.') != string::npos) {
973 /* old school version format */
974 if (prop->value()[0] == '2') {
975 Stateful::loading_state_version = 2000;
977 Stateful::loading_state_version = 3000;
980 Stateful::loading_state_version = atoi (prop->value());
984 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
986 std::string backup_path(_session_dir->root_path());
987 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
988 backup_path = Glib::build_filename (backup_path, backup_filename);
990 // only create a backup for a given statefile version once
992 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
994 VersionMismatch (xmlpath, backup_path);
996 if (!copy_file (xmlpath, backup_path)) {;
1002 save_snapshot_name (snapshot_name);
1008 Session::load_options (const XMLNode& node)
1011 config.set_variables (node);
1016 Session::save_default_options ()
1018 return config.save_state();
1022 Session::get_state()
1028 Session::get_template()
1030 /* if we don't disable rec-enable, diskstreams
1031 will believe they need to store their capture
1032 sources in their state node.
1035 disable_record (false);
1037 return state(false);
1041 Session::state (bool full_state)
1044 XMLNode* node = new XMLNode("Session");
1048 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1049 node->add_property("version", buf);
1051 /* store configuration settings */
1055 node->add_property ("name", _name);
1056 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1057 node->add_property ("sample-rate", buf);
1059 if (session_dirs.size() > 1) {
1063 vector<space_and_path>::iterator i = session_dirs.begin();
1064 vector<space_and_path>::iterator next;
1066 ++i; /* skip the first one */
1070 while (i != session_dirs.end()) {
1074 if (next != session_dirs.end()) {
1075 p += G_SEARCHPATH_SEPARATOR;
1084 child = node->add_child ("Path");
1085 child->add_content (p);
1089 /* save the ID counter */
1091 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1092 node->add_property ("id-counter", buf);
1094 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1095 node->add_property ("name-counter", buf);
1097 /* save the event ID counter */
1099 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1100 node->add_property ("event-counter", buf);
1102 /* various options */
1104 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1105 if (!midi_port_nodes.empty()) {
1106 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1107 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1108 midi_port_stuff->add_child_nocopy (**n);
1110 node->add_child_nocopy (*midi_port_stuff);
1113 node->add_child_nocopy (config.get_variables ());
1115 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1117 child = node->add_child ("Sources");
1120 Glib::Threads::Mutex::Lock sl (source_lock);
1122 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1124 /* Don't save information about non-file Sources, or
1125 * about non-destructive file sources that are empty
1126 * and unused by any regions.
1129 boost::shared_ptr<FileSource> fs;
1131 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1133 if (!fs->destructive()) {
1134 if (fs->empty() && !fs->used()) {
1139 child->add_child_nocopy (siter->second->get_state());
1144 child = node->add_child ("Regions");
1147 Glib::Threads::Mutex::Lock rl (region_lock);
1148 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1149 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1150 boost::shared_ptr<Region> r = i->second;
1151 /* only store regions not attached to playlists */
1152 if (r->playlist() == 0) {
1153 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1154 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1156 child->add_child_nocopy (r->get_state ());
1161 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1163 if (!cassocs.empty()) {
1164 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1166 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1168 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1169 i->first->id().print (buf, sizeof (buf));
1170 can->add_property (X_("copy"), buf);
1171 i->second->id().print (buf, sizeof (buf));
1172 can->add_property (X_("original"), buf);
1173 ca->add_child_nocopy (*can);
1183 node->add_child_nocopy (_locations->get_state());
1186 Locations loc (*this);
1187 // for a template, just create a new Locations, populate it
1188 // with the default start and end, and get the state for that.
1189 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1190 range->set (max_framepos, 0);
1192 XMLNode& locations_state = loc.get_state();
1194 if (ARDOUR::Profile->get_trx() && _locations) {
1195 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1196 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1197 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1198 locations_state.add_child_nocopy ((*i)->get_state ());
1202 node->add_child_nocopy (locations_state);
1205 child = node->add_child ("Bundles");
1207 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1208 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1209 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1211 child->add_child_nocopy (b->get_state());
1216 child = node->add_child ("Routes");
1218 boost::shared_ptr<RouteList> r = routes.reader ();
1220 RoutePublicOrderSorter cmp;
1221 RouteList public_order (*r);
1222 public_order.sort (cmp);
1224 /* the sort should have put control outs first */
1227 assert (_monitor_out == public_order.front());
1230 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1231 if (!(*i)->is_auditioner()) {
1233 child->add_child_nocopy ((*i)->get_state());
1235 child->add_child_nocopy ((*i)->get_template());
1241 playlists->add_state (node, full_state);
1243 child = node->add_child ("RouteGroups");
1244 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1245 child->add_child_nocopy ((*i)->get_state());
1249 XMLNode* gain_child = node->add_child ("Click");
1250 gain_child->add_child_nocopy (_click_io->state (full_state));
1251 gain_child->add_child_nocopy (_click_gain->state (full_state));
1255 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1256 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1260 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1261 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1264 node->add_child_nocopy (_speakers->get_state());
1265 node->add_child_nocopy (_tempo_map->get_state());
1266 node->add_child_nocopy (get_control_protocol_state());
1269 node->add_child_copy (*_extra_xml);
1273 Glib::Threads::Mutex::Lock lm (lua_lock);
1276 luabridge::LuaRef savedstate ((*_lua_save)());
1277 saved = savedstate.cast<std::string>();
1279 lua.collect_garbage ();
1282 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1283 std::string b64s (b64);
1286 XMLNode* script_node = new XMLNode (X_("Script"));
1287 script_node->add_property (X_("lua"), LUA_VERSION);
1288 script_node->add_content (b64s);
1289 node->add_child_nocopy (*script_node);
1296 Session::get_control_protocol_state ()
1298 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1299 return cpm.get_state();
1303 Session::set_state (const XMLNode& node, int version)
1308 XMLProperty const * prop;
1311 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1313 if (node.name() != X_("Session")) {
1314 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1318 if ((prop = node.property ("name")) != 0) {
1319 _name = prop->value ();
1322 if ((prop = node.property (X_("sample-rate"))) != 0) {
1324 _base_frame_rate = atoi (prop->value());
1325 _nominal_frame_rate = _base_frame_rate;
1327 assert (AudioEngine::instance()->running ());
1328 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1329 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1330 if (r.get_value_or (0)) {
1336 setup_raid_path(_session_dir->root_path());
1338 if ((prop = node.property (X_("id-counter"))) != 0) {
1340 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1341 ID::init_counter (x);
1343 /* old sessions used a timebased counter, so fake
1344 the startup ID counter based on a standard
1349 ID::init_counter (now);
1352 if ((prop = node.property (X_("name-counter"))) != 0) {
1353 init_name_id_counter (atoi (prop->value()));
1356 if ((prop = node.property (X_("event-counter"))) != 0) {
1357 Evoral::init_event_id_counter (atoi (prop->value()));
1360 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1361 _midi_ports->set_midi_port_states (child->children());
1364 IO::disable_connecting ();
1366 Stateful::save_extra_xml (node);
1368 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1369 load_options (*child);
1370 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1371 load_options (*child);
1373 error << _("Session: XML state has no options section") << endmsg;
1376 if (version >= 3000) {
1377 if ((child = find_named_node (node, "Metadata")) == 0) {
1378 warning << _("Session: XML state has no metadata section") << endmsg;
1379 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1384 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1385 _speakers->set_state (*child, version);
1388 if ((child = find_named_node (node, "Sources")) == 0) {
1389 error << _("Session: XML state has no sources section") << endmsg;
1391 } else if (load_sources (*child)) {
1395 if ((child = find_named_node (node, "TempoMap")) == 0) {
1396 error << _("Session: XML state has no Tempo Map section") << endmsg;
1398 } else if (_tempo_map->set_state (*child, version)) {
1402 if ((child = find_named_node (node, "Locations")) == 0) {
1403 error << _("Session: XML state has no locations section") << endmsg;
1405 } else if (_locations->set_state (*child, version)) {
1409 locations_changed ();
1411 if (_session_range_location) {
1412 AudioFileSource::set_header_position_offset (_session_range_location->start());
1415 if ((child = find_named_node (node, "Regions")) == 0) {
1416 error << _("Session: XML state has no Regions section") << endmsg;
1418 } else if (load_regions (*child)) {
1422 if ((child = find_named_node (node, "Playlists")) == 0) {
1423 error << _("Session: XML state has no playlists section") << endmsg;
1425 } else if (playlists->load (*this, *child)) {
1429 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1431 } else if (playlists->load_unused (*this, *child)) {
1435 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1436 if (load_compounds (*child)) {
1441 if (version >= 3000) {
1442 if ((child = find_named_node (node, "Bundles")) == 0) {
1443 warning << _("Session: XML state has no bundles section") << endmsg;
1446 /* We can't load Bundles yet as they need to be able
1447 to convert from port names to Port objects, which can't happen until
1449 _bundle_xml_node = new XMLNode (*child);
1453 if (version < 3000) {
1454 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1455 error << _("Session: XML state has no diskstreams section") << endmsg;
1457 } else if (load_diskstreams_2X (*child, version)) {
1462 if ((child = find_named_node (node, "Routes")) == 0) {
1463 error << _("Session: XML state has no routes section") << endmsg;
1465 } else if (load_routes (*child, version)) {
1469 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1470 _diskstreams_2X.clear ();
1472 if (version >= 3000) {
1474 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1475 error << _("Session: XML state has no route groups section") << endmsg;
1477 } else if (load_route_groups (*child, version)) {
1481 } else if (version < 3000) {
1483 if ((child = find_named_node (node, "EditGroups")) == 0) {
1484 error << _("Session: XML state has no edit groups section") << endmsg;
1486 } else if (load_route_groups (*child, version)) {
1490 if ((child = find_named_node (node, "MixGroups")) == 0) {
1491 error << _("Session: XML state has no mix groups section") << endmsg;
1493 } else if (load_route_groups (*child, version)) {
1498 if ((child = find_named_node (node, "Click")) == 0) {
1499 warning << _("Session: XML state has no click section") << endmsg;
1500 } else if (_click_io) {
1501 setup_click_state (&node);
1504 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1505 ControlProtocolManager::instance().set_state (*child, version);
1508 if ((child = find_named_node (node, "Script"))) {
1509 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1510 if (!(*n)->is_content ()) { continue; }
1512 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1514 Glib::Threads::Mutex::Lock lm (lua_lock);
1515 (*_lua_load)(std::string ((const char*)buf, size));
1516 } catch (luabridge::LuaException const& e) {
1517 cerr << "LuaException:" << e.what () << endl;
1523 update_route_record_state ();
1525 /* here beginneth the second phase ... */
1526 set_snapshot_name (_current_snapshot_name);
1528 StateReady (); /* EMIT SIGNAL */
1541 Session::load_routes (const XMLNode& node, int version)
1544 XMLNodeConstIterator niter;
1545 RouteList new_routes;
1547 nlist = node.children();
1551 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1553 boost::shared_ptr<Route> route;
1554 if (version < 3000) {
1555 route = XMLRouteFactory_2X (**niter, version);
1557 route = XMLRouteFactory (**niter, version);
1561 error << _("Session: cannot create Route from XML description.") << endmsg;
1565 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1567 new_routes.push_back (route);
1570 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1572 add_routes (new_routes, false, false, false);
1574 BootMessage (_("Finished adding tracks/busses"));
1579 boost::shared_ptr<Route>
1580 Session::XMLRouteFactory (const XMLNode& node, int version)
1582 boost::shared_ptr<Route> ret;
1584 if (node.name() != "Route") {
1588 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1590 DataType type = DataType::AUDIO;
1591 XMLProperty const * prop = node.property("default-type");
1594 type = DataType (prop->value());
1597 assert (type != DataType::NIL);
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 BOOST_MARK_TRACK (track);
1621 enum Route::Flag flags = Route::Flag(0);
1622 XMLProperty const * prop = node.property("flags");
1624 flags = Route::Flag (string_2_enum (prop->value(), flags));
1627 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1629 if (r->init () == 0 && r->set_state (node, version) == 0) {
1630 BOOST_MARK_ROUTE (r);
1638 boost::shared_ptr<Route>
1639 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1641 boost::shared_ptr<Route> ret;
1643 if (node.name() != "Route") {
1647 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1649 ds_prop = node.property (X_("diskstream"));
1652 DataType type = DataType::AUDIO;
1653 XMLProperty const * prop = node.property("default-type");
1656 type = DataType (prop->value());
1659 assert (type != DataType::NIL);
1663 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1664 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1668 if (i == _diskstreams_2X.end()) {
1669 error << _("Could not find diskstream for route") << endmsg;
1670 return boost::shared_ptr<Route> ();
1673 boost::shared_ptr<Track> track;
1675 if (type == DataType::AUDIO) {
1676 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1678 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1681 if (track->init()) {
1685 if (track->set_state (node, version)) {
1689 track->set_diskstream (*i);
1691 BOOST_MARK_TRACK (track);
1695 enum Route::Flag flags = Route::Flag(0);
1696 XMLProperty const * prop = node.property("flags");
1698 flags = Route::Flag (string_2_enum (prop->value(), flags));
1701 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1703 if (r->init () == 0 && r->set_state (node, version) == 0) {
1704 BOOST_MARK_ROUTE (r);
1713 Session::load_regions (const XMLNode& node)
1716 XMLNodeConstIterator niter;
1717 boost::shared_ptr<Region> region;
1719 nlist = node.children();
1723 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1724 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1725 error << _("Session: cannot create Region from XML description.");
1726 XMLProperty const * name = (**niter).property("name");
1729 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1740 Session::load_compounds (const XMLNode& node)
1742 XMLNodeList calist = node.children();
1743 XMLNodeConstIterator caiter;
1744 XMLProperty const * caprop;
1746 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1747 XMLNode* ca = *caiter;
1751 if ((caprop = ca->property (X_("original"))) == 0) {
1754 orig_id = caprop->value();
1756 if ((caprop = ca->property (X_("copy"))) == 0) {
1759 copy_id = caprop->value();
1761 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1762 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1764 if (!orig || !copy) {
1765 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1771 RegionFactory::add_compound_association (orig, copy);
1778 Session::load_nested_sources (const XMLNode& node)
1781 XMLNodeConstIterator niter;
1783 nlist = node.children();
1785 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1786 if ((*niter)->name() == "Source") {
1788 /* it may already exist, so don't recreate it unnecessarily
1791 XMLProperty const * prop = (*niter)->property (X_("id"));
1793 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1797 ID source_id (prop->value());
1799 if (!source_by_id (source_id)) {
1802 SourceFactory::create (*this, **niter, true);
1804 catch (failed_constructor& err) {
1805 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1812 boost::shared_ptr<Region>
1813 Session::XMLRegionFactory (const XMLNode& node, bool full)
1815 XMLProperty const * type = node.property("type");
1819 const XMLNodeList& nlist = node.children();
1821 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1822 XMLNode *child = (*niter);
1823 if (child->name() == "NestedSource") {
1824 load_nested_sources (*child);
1828 if (!type || type->value() == "audio") {
1829 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1830 } else if (type->value() == "midi") {
1831 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1834 } catch (failed_constructor& err) {
1835 return boost::shared_ptr<Region> ();
1838 return boost::shared_ptr<Region> ();
1841 boost::shared_ptr<AudioRegion>
1842 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1844 XMLProperty const * prop;
1845 boost::shared_ptr<Source> source;
1846 boost::shared_ptr<AudioSource> as;
1848 SourceList master_sources;
1849 uint32_t nchans = 1;
1852 if (node.name() != X_("Region")) {
1853 return boost::shared_ptr<AudioRegion>();
1856 if ((prop = node.property (X_("channels"))) != 0) {
1857 nchans = atoi (prop->value().c_str());
1860 if ((prop = node.property ("name")) == 0) {
1861 cerr << "no name for this region\n";
1865 if ((prop = node.property (X_("source-0"))) == 0) {
1866 if ((prop = node.property ("source")) == 0) {
1867 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1868 return boost::shared_ptr<AudioRegion>();
1872 PBD::ID s_id (prop->value());
1874 if ((source = source_by_id (s_id)) == 0) {
1875 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1876 return boost::shared_ptr<AudioRegion>();
1879 as = boost::dynamic_pointer_cast<AudioSource>(source);
1881 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1882 return boost::shared_ptr<AudioRegion>();
1885 sources.push_back (as);
1887 /* pickup other channels */
1889 for (uint32_t n=1; n < nchans; ++n) {
1890 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1891 if ((prop = node.property (buf)) != 0) {
1893 PBD::ID id2 (prop->value());
1895 if ((source = source_by_id (id2)) == 0) {
1896 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1897 return boost::shared_ptr<AudioRegion>();
1900 as = boost::dynamic_pointer_cast<AudioSource>(source);
1902 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1903 return boost::shared_ptr<AudioRegion>();
1905 sources.push_back (as);
1909 for (uint32_t n = 0; n < nchans; ++n) {
1910 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1911 if ((prop = node.property (buf)) != 0) {
1913 PBD::ID id2 (prop->value());
1915 if ((source = source_by_id (id2)) == 0) {
1916 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1917 return boost::shared_ptr<AudioRegion>();
1920 as = boost::dynamic_pointer_cast<AudioSource>(source);
1922 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1923 return boost::shared_ptr<AudioRegion>();
1925 master_sources.push_back (as);
1930 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1932 /* a final detail: this is the one and only place that we know how long missing files are */
1934 if (region->whole_file()) {
1935 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1936 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1938 sfp->set_length (region->length());
1943 if (!master_sources.empty()) {
1944 if (master_sources.size() != nchans) {
1945 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1947 region->set_master_sources (master_sources);
1955 catch (failed_constructor& err) {
1956 return boost::shared_ptr<AudioRegion>();
1960 boost::shared_ptr<MidiRegion>
1961 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1963 XMLProperty const * prop;
1964 boost::shared_ptr<Source> source;
1965 boost::shared_ptr<MidiSource> ms;
1968 if (node.name() != X_("Region")) {
1969 return boost::shared_ptr<MidiRegion>();
1972 if ((prop = node.property ("name")) == 0) {
1973 cerr << "no name for this region\n";
1977 if ((prop = node.property (X_("source-0"))) == 0) {
1978 if ((prop = node.property ("source")) == 0) {
1979 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1980 return boost::shared_ptr<MidiRegion>();
1984 PBD::ID s_id (prop->value());
1986 if ((source = source_by_id (s_id)) == 0) {
1987 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1988 return boost::shared_ptr<MidiRegion>();
1991 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1993 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1994 return boost::shared_ptr<MidiRegion>();
1997 sources.push_back (ms);
2000 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2001 /* a final detail: this is the one and only place that we know how long missing files are */
2003 if (region->whole_file()) {
2004 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2005 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2007 sfp->set_length (region->length());
2015 catch (failed_constructor& err) {
2016 return boost::shared_ptr<MidiRegion>();
2021 Session::get_sources_as_xml ()
2024 XMLNode* node = new XMLNode (X_("Sources"));
2025 Glib::Threads::Mutex::Lock lm (source_lock);
2027 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2028 node->add_child_nocopy (i->second->get_state());
2035 Session::reset_write_sources (bool mark_write_complete, bool force)
2037 boost::shared_ptr<RouteList> rl = routes.reader();
2038 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2039 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2041 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2042 tr->reset_write_sources(mark_write_complete, force);
2043 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2049 Session::load_sources (const XMLNode& node)
2052 XMLNodeConstIterator niter;
2053 boost::shared_ptr<Source> source; /* don't need this but it stops some
2054 * versions of gcc complaining about
2055 * discarded return values.
2058 nlist = node.children();
2062 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2065 if ((source = XMLSourceFactory (**niter)) == 0) {
2066 error << _("Session: cannot create Source from XML description.") << endmsg;
2069 } catch (MissingSource& err) {
2073 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2074 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2075 PROGRAM_NAME) << endmsg;
2079 if (!no_questions_about_missing_files) {
2080 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2085 switch (user_choice) {
2087 /* user added a new search location, so try again */
2092 /* user asked to quit the entire session load
2097 no_questions_about_missing_files = true;
2101 no_questions_about_missing_files = true;
2108 case DataType::AUDIO:
2109 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2112 case DataType::MIDI:
2113 /* The MIDI file is actually missing so
2114 * just create a new one in the same
2115 * location. Do not announce its
2119 if (!Glib::path_is_absolute (err.path)) {
2120 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2122 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2127 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2128 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2129 /* reset ID to match the missing one */
2130 source->set_id (**niter);
2131 /* Now we can announce it */
2132 SourceFactory::SourceCreated (source);
2143 boost::shared_ptr<Source>
2144 Session::XMLSourceFactory (const XMLNode& node)
2146 if (node.name() != "Source") {
2147 return boost::shared_ptr<Source>();
2151 /* note: do peak building in another thread when loading session state */
2152 return SourceFactory::create (*this, node, true);
2155 catch (failed_constructor& err) {
2156 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2157 return boost::shared_ptr<Source>();
2162 Session::save_template (string template_name, bool replace_existing)
2164 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2168 bool absolute_path = Glib::path_is_absolute (template_name);
2170 /* directory to put the template in */
2171 std::string template_dir_path;
2173 if (!absolute_path) {
2174 std::string user_template_dir(user_template_directory());
2176 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2177 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2178 user_template_dir, g_strerror (errno)) << endmsg;
2182 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2184 template_dir_path = template_name;
2187 if (!ARDOUR::Profile->get_trx()) {
2188 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2189 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2190 template_dir_path) << endmsg;
2194 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2195 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2196 template_dir_path, g_strerror (errno)) << endmsg;
2202 std::string template_file_path;
2204 if (ARDOUR::Profile->get_trx()) {
2205 template_file_path = template_name;
2207 if (absolute_path) {
2208 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2210 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2214 SessionSaveUnderway (); /* EMIT SIGNAL */
2219 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2220 tree.set_root (&get_template());
2223 if (!tree.write (template_file_path)) {
2224 error << _("template not saved") << endmsg;
2228 store_recent_templates (template_file_path);
2234 Session::refresh_disk_space ()
2236 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2238 Glib::Threads::Mutex::Lock lm (space_lock);
2240 /* get freespace on every FS that is part of the session path */
2242 _total_free_4k_blocks = 0;
2243 _total_free_4k_blocks_uncertain = false;
2245 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2247 struct statfs statfsbuf;
2248 statfs (i->path.c_str(), &statfsbuf);
2250 double const scale = statfsbuf.f_bsize / 4096.0;
2252 /* See if this filesystem is read-only */
2253 struct statvfs statvfsbuf;
2254 statvfs (i->path.c_str(), &statvfsbuf);
2256 /* f_bavail can be 0 if it is undefined for whatever
2257 filesystem we are looking at; Samba shares mounted
2258 via GVFS are an example of this.
2260 if (statfsbuf.f_bavail == 0) {
2261 /* block count unknown */
2263 i->blocks_unknown = true;
2264 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2265 /* read-only filesystem */
2267 i->blocks_unknown = false;
2269 /* read/write filesystem with known space */
2270 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2271 i->blocks_unknown = false;
2274 _total_free_4k_blocks += i->blocks;
2275 if (i->blocks_unknown) {
2276 _total_free_4k_blocks_uncertain = true;
2279 #elif defined PLATFORM_WINDOWS
2280 vector<string> scanned_volumes;
2281 vector<string>::iterator j;
2282 vector<space_and_path>::iterator i;
2283 DWORD nSectorsPerCluster, nBytesPerSector,
2284 nFreeClusters, nTotalClusters;
2288 _total_free_4k_blocks = 0;
2290 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2291 strncpy (disk_drive, (*i).path.c_str(), 3);
2295 volume_found = false;
2296 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2298 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2299 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2300 i->blocks = (uint32_t)(nFreeBytes / 4096);
2302 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2303 if (0 == j->compare(disk_drive)) {
2304 volume_found = true;
2309 if (!volume_found) {
2310 scanned_volumes.push_back(disk_drive);
2311 _total_free_4k_blocks += i->blocks;
2316 if (0 == _total_free_4k_blocks) {
2317 strncpy (disk_drive, path().c_str(), 3);
2320 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2322 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2323 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2324 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2331 Session::get_best_session_directory_for_new_audio ()
2333 vector<space_and_path>::iterator i;
2334 string result = _session_dir->root_path();
2336 /* handle common case without system calls */
2338 if (session_dirs.size() == 1) {
2342 /* OK, here's the algorithm we're following here:
2344 We want to select which directory to use for
2345 the next file source to be created. Ideally,
2346 we'd like to use a round-robin process so as to
2347 get maximum performance benefits from splitting
2348 the files across multiple disks.
2350 However, in situations without much diskspace, an
2351 RR approach may end up filling up a filesystem
2352 with new files while others still have space.
2353 Its therefore important to pay some attention to
2354 the freespace in the filesystem holding each
2355 directory as well. However, if we did that by
2356 itself, we'd keep creating new files in the file
2357 system with the most space until it was as full
2358 as all others, thus negating any performance
2359 benefits of this RAID-1 like approach.
2361 So, we use a user-configurable space threshold. If
2362 there are at least 2 filesystems with more than this
2363 much space available, we use RR selection between them.
2364 If not, then we pick the filesystem with the most space.
2366 This gets a good balance between the two
2370 refresh_disk_space ();
2372 int free_enough = 0;
2374 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2375 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2380 if (free_enough >= 2) {
2381 /* use RR selection process, ensuring that the one
2385 i = last_rr_session_dir;
2388 if (++i == session_dirs.end()) {
2389 i = session_dirs.begin();
2392 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2393 SessionDirectory sdir(i->path);
2394 if (sdir.create ()) {
2396 last_rr_session_dir = i;
2401 } while (i != last_rr_session_dir);
2405 /* pick FS with the most freespace (and that
2406 seems to actually work ...)
2409 vector<space_and_path> sorted;
2410 space_and_path_ascending_cmp cmp;
2412 sorted = session_dirs;
2413 sort (sorted.begin(), sorted.end(), cmp);
2415 for (i = sorted.begin(); i != sorted.end(); ++i) {
2416 SessionDirectory sdir(i->path);
2417 if (sdir.create ()) {
2419 last_rr_session_dir = i;
2429 Session::automation_dir () const
2431 return Glib::build_filename (_path, automation_dir_name);
2435 Session::analysis_dir () const
2437 return Glib::build_filename (_path, analysis_dir_name);
2441 Session::plugins_dir () const
2443 return Glib::build_filename (_path, plugins_dir_name);
2447 Session::externals_dir () const
2449 return Glib::build_filename (_path, externals_dir_name);
2453 Session::load_bundles (XMLNode const & node)
2455 XMLNodeList nlist = node.children();
2456 XMLNodeConstIterator niter;
2460 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2461 if ((*niter)->name() == "InputBundle") {
2462 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2463 } else if ((*niter)->name() == "OutputBundle") {
2464 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2466 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2475 Session::load_route_groups (const XMLNode& node, int version)
2477 XMLNodeList nlist = node.children();
2478 XMLNodeConstIterator niter;
2482 if (version >= 3000) {
2484 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2485 if ((*niter)->name() == "RouteGroup") {
2486 RouteGroup* rg = new RouteGroup (*this, "");
2487 add_route_group (rg);
2488 rg->set_state (**niter, version);
2492 } else if (version < 3000) {
2494 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2495 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2496 RouteGroup* rg = new RouteGroup (*this, "");
2497 add_route_group (rg);
2498 rg->set_state (**niter, version);
2507 state_file_filter (const string &str, void* /*arg*/)
2509 return (str.length() > strlen(statefile_suffix) &&
2510 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2514 remove_end(string state)
2516 string statename(state);
2518 string::size_type start,end;
2519 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2520 statename = statename.substr (start+1);
2523 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2524 end = statename.length();
2527 return string(statename.substr (0, end));
2531 Session::possible_states (string path)
2533 vector<string> states;
2534 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2536 transform(states.begin(), states.end(), states.begin(), remove_end);
2538 sort (states.begin(), states.end());
2544 Session::possible_states () const
2546 return possible_states(_path);
2550 Session::add_route_group (RouteGroup* g)
2552 _route_groups.push_back (g);
2553 route_group_added (g); /* EMIT SIGNAL */
2555 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2556 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2557 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2563 Session::remove_route_group (RouteGroup& rg)
2565 list<RouteGroup*>::iterator i;
2567 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2568 _route_groups.erase (i);
2571 route_group_removed (); /* EMIT SIGNAL */
2575 /** Set a new order for our route groups, without adding or removing any.
2576 * @param groups Route group list in the new order.
2579 Session::reorder_route_groups (list<RouteGroup*> groups)
2581 _route_groups = groups;
2583 route_groups_reordered (); /* EMIT SIGNAL */
2589 Session::route_group_by_name (string name)
2591 list<RouteGroup *>::iterator i;
2593 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2594 if ((*i)->name() == name) {
2602 Session::all_route_group() const
2604 return *_all_route_group;
2608 Session::add_commands (vector<Command*> const & cmds)
2610 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2616 Session::add_command (Command* const cmd)
2618 assert (_current_trans);
2619 DEBUG_UNDO_HISTORY (
2620 string_compose ("Current Undo Transaction %1, adding command: %2",
2621 _current_trans->name (),
2623 _current_trans->add_command (cmd);
2626 PBD::StatefulDiffCommand*
2627 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2629 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2635 Session::begin_reversible_command (const string& name)
2637 begin_reversible_command (g_quark_from_string (name.c_str ()));
2640 /** Begin a reversible command using a GQuark to identify it.
2641 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2642 * but there must be as many begin...()s as there are commit...()s.
2645 Session::begin_reversible_command (GQuark q)
2647 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2648 to hold all the commands that are committed. This keeps the order of
2649 commands correct in the history.
2652 if (_current_trans == 0) {
2653 DEBUG_UNDO_HISTORY (string_compose (
2654 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2656 /* start a new transaction */
2657 assert (_current_trans_quarks.empty ());
2658 _current_trans = new UndoTransaction();
2659 _current_trans->set_name (g_quark_to_string (q));
2661 DEBUG_UNDO_HISTORY (
2662 string_compose ("Begin Reversible Command, current transaction: %1",
2663 _current_trans->name ()));
2666 _current_trans_quarks.push_front (q);
2670 Session::abort_reversible_command ()
2672 if (_current_trans != 0) {
2673 DEBUG_UNDO_HISTORY (
2674 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2675 _current_trans->clear();
2676 delete _current_trans;
2678 _current_trans_quarks.clear();
2683 Session::commit_reversible_command (Command *cmd)
2685 assert (_current_trans);
2686 assert (!_current_trans_quarks.empty ());
2691 DEBUG_UNDO_HISTORY (
2692 string_compose ("Current Undo Transaction %1, adding command: %2",
2693 _current_trans->name (),
2695 _current_trans->add_command (cmd);
2698 DEBUG_UNDO_HISTORY (
2699 string_compose ("Commit Reversible Command, current transaction: %1",
2700 _current_trans->name ()));
2702 _current_trans_quarks.pop_front ();
2704 if (!_current_trans_quarks.empty ()) {
2705 DEBUG_UNDO_HISTORY (
2706 string_compose ("Commit Reversible Command, transaction is not "
2707 "top-level, current transaction: %1",
2708 _current_trans->name ()));
2709 /* the transaction we're committing is not the top-level one */
2713 if (_current_trans->empty()) {
2714 /* no commands were added to the transaction, so just get rid of it */
2715 DEBUG_UNDO_HISTORY (
2716 string_compose ("Commit Reversible Command, No commands were "
2717 "added to current transaction: %1",
2718 _current_trans->name ()));
2719 delete _current_trans;
2724 gettimeofday (&now, 0);
2725 _current_trans->set_timestamp (now);
2727 _history.add (_current_trans);
2732 accept_all_audio_files (const string& path, void* /*arg*/)
2734 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2738 if (!AudioFileSource::safe_audio_file_extension (path)) {
2746 accept_all_midi_files (const string& path, void* /*arg*/)
2748 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2752 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2753 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2754 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2758 accept_all_state_files (const string& path, void* /*arg*/)
2760 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2764 std::string const statefile_ext (statefile_suffix);
2765 if (path.length() >= statefile_ext.length()) {
2766 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2773 Session::find_all_sources (string path, set<string>& result)
2778 if (!tree.read (path)) {
2782 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2787 XMLNodeConstIterator niter;
2789 nlist = node->children();
2793 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2795 XMLProperty const * prop;
2797 if ((prop = (*niter)->property (X_("type"))) == 0) {
2801 DataType type (prop->value());
2803 if ((prop = (*niter)->property (X_("name"))) == 0) {
2807 if (Glib::path_is_absolute (prop->value())) {
2808 /* external file, ignore */
2816 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2817 result.insert (found_path);
2825 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2827 vector<string> state_files;
2829 string this_snapshot_path;
2835 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2836 ripped = ripped.substr (0, ripped.length() - 1);
2839 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2841 if (state_files.empty()) {
2846 this_snapshot_path = _path;
2847 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2848 this_snapshot_path += statefile_suffix;
2850 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2852 if (exclude_this_snapshot && *i == this_snapshot_path) {
2856 if (find_all_sources (*i, result) < 0) {
2864 struct RegionCounter {
2865 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2866 AudioSourceList::iterator iter;
2867 boost::shared_ptr<Region> region;
2870 RegionCounter() : count (0) {}
2874 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2876 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2877 return r.get_value_or (1);
2881 Session::cleanup_regions ()
2883 bool removed = false;
2884 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2886 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2888 uint32_t used = playlists->region_use_count (i->second);
2890 if (used == 0 && !i->second->automatic ()) {
2891 boost::weak_ptr<Region> w = i->second;
2894 RegionFactory::map_remove (w);
2901 // re-check to remove parent references of compound regions
2902 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2903 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2907 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2908 if (0 == playlists->region_use_count (i->second)) {
2909 boost::weak_ptr<Region> w = i->second;
2911 RegionFactory::map_remove (w);
2918 /* dump the history list */
2925 Session::can_cleanup_peakfiles () const
2927 if (deletion_in_progress()) {
2930 if (!_writable || (_state_of_the_state & CannotSave)) {
2931 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2934 if (record_status() == Recording) {
2935 error << _("Cannot cleanup peak-files while recording") << endmsg;
2942 Session::cleanup_peakfiles ()
2944 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2949 assert (can_cleanup_peakfiles ());
2950 assert (!peaks_cleanup_in_progres());
2952 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2954 int timeout = 5000; // 5 seconds
2955 while (!SourceFactory::files_with_peaks.empty()) {
2956 Glib::usleep (1000);
2957 if (--timeout < 0) {
2958 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2959 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2964 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2965 boost::shared_ptr<AudioSource> as;
2966 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2967 as->close_peakfile();
2971 PBD::clear_directory (session_directory().peak_path());
2973 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2975 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2976 boost::shared_ptr<AudioSource> as;
2977 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2978 SourceFactory::setup_peakfile(as, true);
2985 Session::cleanup_sources (CleanupReport& rep)
2987 // FIXME: needs adaptation to midi
2989 vector<boost::shared_ptr<Source> > dead_sources;
2992 vector<string> candidates;
2993 vector<string> unused;
2994 set<string> all_sources;
3003 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3005 /* this is mostly for windows which doesn't allow file
3006 * renaming if the file is in use. But we don't special
3007 * case it because we need to know if this causes
3008 * problems, and the easiest way to notice that is to
3009 * keep it in place for all platforms.
3012 request_stop (false);
3014 _butler->wait_until_finished ();
3016 /* consider deleting all unused playlists */
3018 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3023 /* sync the "all regions" property of each playlist with its current state
3026 playlists->sync_all_regions_with_regions ();
3028 /* find all un-used sources */
3033 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3035 SourceMap::iterator tmp;
3040 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3044 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
3045 dead_sources.push_back (i->second);
3046 i->second->drop_references ();
3052 /* build a list of all the possible audio directories for the session */
3054 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3055 SessionDirectory sdir ((*i).path);
3056 asp += sdir.sound_path();
3058 audio_path += asp.to_string();
3061 /* build a list of all the possible midi directories for the session */
3063 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3064 SessionDirectory sdir ((*i).path);
3065 msp += sdir.midi_path();
3067 midi_path += msp.to_string();
3069 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3070 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3072 /* find all sources, but don't use this snapshot because the
3073 state file on disk still references sources we may have already
3077 find_all_sources_across_snapshots (all_sources, true);
3079 /* add our current source list
3082 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3083 boost::shared_ptr<FileSource> fs;
3084 SourceMap::iterator tmp = i;
3087 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3089 /* this is mostly for windows which doesn't allow file
3090 * renaming if the file is in use. But we don't special
3091 * case it because we need to know if this causes
3092 * problems, and the easiest way to notice that is to
3093 * keep it in place for all platforms.
3098 if (!fs->is_stub()) {
3100 if (playlists->source_use_count (fs) != 0) {
3101 all_sources.insert (fs->path());
3104 /* we might not remove this source from disk, because it may be used
3105 by other snapshots, but its not being used in this version
3106 so lets get rid of it now, along with any representative regions
3110 RegionFactory::remove_regions_using_source (i->second);
3112 // also remove source from all_sources
3114 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3115 spath = Glib::path_get_basename (*j);
3116 if (spath == i->second->name()) {
3117 all_sources.erase (j);
3130 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3135 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3137 tmppath1 = canonical_path (spath);
3138 tmppath2 = canonical_path ((*i));
3140 if (tmppath1 == tmppath2) {
3147 unused.push_back (spath);
3151 /* now try to move all unused files into the "dead" directory(ies) */
3153 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3158 /* don't move the file across filesystems, just
3159 stick it in the `dead_dir_name' directory
3160 on whichever filesystem it was already on.
3163 if ((*x).find ("/sounds/") != string::npos) {
3165 /* old school, go up 1 level */
3167 newpath = Glib::path_get_dirname (*x); // "sounds"
3168 newpath = Glib::path_get_dirname (newpath); // "session-name"
3172 /* new school, go up 4 levels */
3174 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3175 newpath = Glib::path_get_dirname (newpath); // "session-name"
3176 newpath = Glib::path_get_dirname (newpath); // "interchange"
3177 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3180 newpath = Glib::build_filename (newpath, dead_dir_name);
3182 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3183 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3187 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3189 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3191 /* the new path already exists, try versioning */
3193 char buf[PATH_MAX+1];
3197 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3200 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3201 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3205 if (version == 999) {
3206 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3210 newpath = newpath_v;
3215 /* it doesn't exist, or we can't read it or something */
3219 g_stat ((*x).c_str(), &statbuf);
3221 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3222 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3223 (*x), newpath, strerror (errno))
3228 /* see if there an easy to find peakfile for this file, and remove it.
3231 string base = Glib::path_get_basename (*x);
3232 base += "%A"; /* this is what we add for the channel suffix of all native files,
3233 or for the first channel of embedded files. it will miss
3234 some peakfiles for other channels
3236 string peakpath = construct_peak_filepath (base);
3238 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3239 if (::g_unlink (peakpath.c_str()) != 0) {
3240 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3241 peakpath, _path, strerror (errno))
3243 /* try to back out */
3244 ::rename (newpath.c_str(), _path.c_str());
3249 rep.paths.push_back (*x);
3250 rep.space += statbuf.st_size;
3253 /* dump the history list */
3257 /* save state so we don't end up a session file
3258 referring to non-existent sources.
3265 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3271 Session::cleanup_trash_sources (CleanupReport& rep)
3273 // FIXME: needs adaptation for MIDI
3275 vector<space_and_path>::iterator i;
3281 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3283 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3285 clear_directory (dead_dir, &rep.space, &rep.paths);
3292 Session::set_dirty ()
3294 /* never mark session dirty during loading */
3296 if (_state_of_the_state & Loading) {
3300 bool was_dirty = dirty();
3302 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3306 DirtyChanged(); /* EMIT SIGNAL */
3312 Session::set_clean ()
3314 bool was_dirty = dirty();
3316 _state_of_the_state = Clean;
3320 DirtyChanged(); /* EMIT SIGNAL */
3325 Session::set_deletion_in_progress ()
3327 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3331 Session::clear_deletion_in_progress ()
3333 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3337 Session::add_controllable (boost::shared_ptr<Controllable> c)
3339 /* this adds a controllable to the list managed by the Session.
3340 this is a subset of those managed by the Controllable class
3341 itself, and represents the only ones whose state will be saved
3342 as part of the session.
3345 Glib::Threads::Mutex::Lock lm (controllables_lock);
3346 controllables.insert (c);
3349 struct null_deleter { void operator()(void const *) const {} };
3352 Session::remove_controllable (Controllable* c)
3354 if (_state_of_the_state & Deletion) {
3358 Glib::Threads::Mutex::Lock lm (controllables_lock);
3360 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3362 if (x != controllables.end()) {
3363 controllables.erase (x);
3367 boost::shared_ptr<Controllable>
3368 Session::controllable_by_id (const PBD::ID& id)
3370 Glib::Threads::Mutex::Lock lm (controllables_lock);
3372 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3373 if ((*i)->id() == id) {
3378 return boost::shared_ptr<Controllable>();
3381 boost::shared_ptr<Controllable>
3382 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3384 boost::shared_ptr<Controllable> c;
3385 boost::shared_ptr<Route> r;
3387 switch (desc.top_level_type()) {
3388 case ControllableDescriptor::NamedRoute:
3390 std::string str = desc.top_level_name();
3391 if (str == "Master" || str == "master") {
3393 } else if (str == "control" || str == "listen") {
3396 r = route_by_name (desc.top_level_name());
3401 case ControllableDescriptor::RemoteControlID:
3402 r = route_by_remote_id (desc.rid());
3405 case ControllableDescriptor::SelectionCount:
3406 r = route_by_selected_count (desc.selection_id());
3414 switch (desc.subtype()) {
3415 case ControllableDescriptor::Gain:
3416 c = r->gain_control ();
3419 case ControllableDescriptor::Trim:
3420 c = r->trim()->gain_control ();
3423 case ControllableDescriptor::Solo:
3424 c = r->solo_control();
3427 case ControllableDescriptor::Mute:
3428 c = r->mute_control();
3431 case ControllableDescriptor::Recenable:
3433 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3436 c = t->rec_enable_control ();
3441 case ControllableDescriptor::PanDirection:
3442 c = r->pan_azimuth_control();
3445 case ControllableDescriptor::PanWidth:
3446 c = r->pan_width_control();
3449 case ControllableDescriptor::PanElevation:
3450 c = r->pan_elevation_control();
3453 case ControllableDescriptor::Balance:
3454 /* XXX simple pan control */
3457 case ControllableDescriptor::PluginParameter:
3459 uint32_t plugin = desc.target (0);
3460 uint32_t parameter_index = desc.target (1);
3462 /* revert to zero based counting */
3468 if (parameter_index > 0) {
3472 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3475 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3476 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3481 case ControllableDescriptor::SendGain: {
3482 uint32_t send = desc.target (0);
3486 c = r->send_level_controllable (send);
3491 /* relax and return a null pointer */
3499 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3502 Stateful::add_instant_xml (node, _path);
3505 if (write_to_config) {
3506 Config->add_instant_xml (node);
3511 Session::instant_xml (const string& node_name)
3513 return Stateful::instant_xml (node_name, _path);
3517 Session::save_history (string snapshot_name)
3525 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3526 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3530 if (snapshot_name.empty()) {
3531 snapshot_name = _current_snapshot_name;
3534 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3535 const string backup_filename = history_filename + backup_suffix;
3536 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3537 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3539 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3540 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3541 error << _("could not backup old history file, current history not saved") << endmsg;
3546 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3548 if (!tree.write (xml_path))
3550 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3552 if (g_remove (xml_path.c_str()) != 0) {
3553 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3554 xml_path, g_strerror (errno)) << endmsg;
3556 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3557 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3558 backup_path, g_strerror (errno)) << endmsg;
3568 Session::restore_history (string snapshot_name)
3572 if (snapshot_name.empty()) {
3573 snapshot_name = _current_snapshot_name;
3576 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3577 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3579 info << "Loading history from " << xml_path << endmsg;
3581 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3582 info << string_compose (_("%1: no history file \"%2\" for this session."),
3583 _name, xml_path) << endmsg;
3587 if (!tree.read (xml_path)) {
3588 error << string_compose (_("Could not understand session history file \"%1\""),
3589 xml_path) << endmsg;
3596 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3599 UndoTransaction* ut = new UndoTransaction ();
3602 ut->set_name(t->property("name")->value());
3603 stringstream ss(t->property("tv-sec")->value());
3605 ss.str(t->property("tv-usec")->value());
3607 ut->set_timestamp(tv);
3609 for (XMLNodeConstIterator child_it = t->children().begin();
3610 child_it != t->children().end(); child_it++)
3612 XMLNode *n = *child_it;
3615 if (n->name() == "MementoCommand" ||
3616 n->name() == "MementoUndoCommand" ||
3617 n->name() == "MementoRedoCommand") {
3619 if ((c = memento_command_factory(n))) {
3623 } else if (n->name() == "NoteDiffCommand") {
3624 PBD::ID id (n->property("midi-source")->value());
3625 boost::shared_ptr<MidiSource> midi_source =
3626 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3628 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3630 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3633 } else if (n->name() == "SysExDiffCommand") {
3635 PBD::ID id (n->property("midi-source")->value());
3636 boost::shared_ptr<MidiSource> midi_source =
3637 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3639 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3641 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3644 } else if (n->name() == "PatchChangeDiffCommand") {
3646 PBD::ID id (n->property("midi-source")->value());
3647 boost::shared_ptr<MidiSource> midi_source =
3648 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3650 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3652 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3655 } else if (n->name() == "StatefulDiffCommand") {
3656 if ((c = stateful_diff_command_factory (n))) {
3657 ut->add_command (c);
3660 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3671 Session::config_changed (std::string p, bool ours)
3677 if (p == "seamless-loop") {
3679 } else if (p == "rf-speed") {
3681 } else if (p == "auto-loop") {
3683 } else if (p == "auto-input") {
3685 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3686 /* auto-input only makes a difference if we're rolling */
3687 set_track_monitor_input_status (!config.get_auto_input());
3690 } else if (p == "punch-in") {
3694 if ((location = _locations->auto_punch_location()) != 0) {
3696 if (config.get_punch_in ()) {
3697 replace_event (SessionEvent::PunchIn, location->start());
3699 remove_event (location->start(), SessionEvent::PunchIn);
3703 } else if (p == "punch-out") {
3707 if ((location = _locations->auto_punch_location()) != 0) {
3709 if (config.get_punch_out()) {
3710 replace_event (SessionEvent::PunchOut, location->end());
3712 clear_events (SessionEvent::PunchOut);
3716 } else if (p == "edit-mode") {
3718 Glib::Threads::Mutex::Lock lm (playlists->lock);
3720 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3721 (*i)->set_edit_mode (Config->get_edit_mode ());
3724 } else if (p == "use-video-sync") {
3726 waiting_for_sync_offset = config.get_use_video_sync();
3728 } else if (p == "mmc-control") {
3730 //poke_midi_thread ();
3732 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3734 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3736 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3738 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3740 } else if (p == "midi-control") {
3742 //poke_midi_thread ();
3744 } else if (p == "raid-path") {
3746 setup_raid_path (config.get_raid_path());
3748 } else if (p == "timecode-format") {
3752 } else if (p == "video-pullup") {
3756 } else if (p == "seamless-loop") {
3758 if (play_loop && transport_rolling()) {
3759 // to reset diskstreams etc
3760 request_play_loop (true);
3763 } else if (p == "rf-speed") {
3765 cumulative_rf_motion = 0;
3768 } else if (p == "click-sound") {
3770 setup_click_sounds (1);
3772 } else if (p == "click-emphasis-sound") {
3774 setup_click_sounds (-1);
3776 } else if (p == "clicking") {
3778 if (Config->get_clicking()) {
3779 if (_click_io && click_data) { // don't require emphasis data
3786 } else if (p == "click-gain") {
3789 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3792 } else if (p == "send-mtc") {
3794 if (Config->get_send_mtc ()) {
3795 /* mark us ready to send */
3796 next_quarter_frame_to_send = 0;
3799 } else if (p == "send-mmc") {
3801 _mmc->enable_send (Config->get_send_mmc ());
3803 } else if (p == "midi-feedback") {
3805 session_midi_feedback = Config->get_midi_feedback();
3807 } else if (p == "jack-time-master") {
3809 engine().reset_timebase ();
3811 } else if (p == "native-file-header-format") {
3813 if (!first_file_header_format_reset) {
3814 reset_native_file_format ();
3817 first_file_header_format_reset = false;
3819 } else if (p == "native-file-data-format") {
3821 if (!first_file_data_format_reset) {
3822 reset_native_file_format ();
3825 first_file_data_format_reset = false;
3827 } else if (p == "external-sync") {
3828 if (!config.get_external_sync()) {
3829 drop_sync_source ();
3831 switch_to_sync_source (Config->get_sync_source());
3833 } else if (p == "denormal-model") {
3835 } else if (p == "history-depth") {
3836 set_history_depth (Config->get_history_depth());
3837 } else if (p == "remote-model") {
3838 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3841 } else if (p == "initial-program-change") {
3843 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3846 buf[0] = MIDI::program; // channel zero by default
3847 buf[1] = (Config->get_initial_program_change() & 0x7f);
3849 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3851 } else if (p == "solo-mute-override") {
3852 // catch_up_on_solo_mute_override ();
3853 } else if (p == "listen-position" || p == "pfl-position") {
3854 listen_position_changed ();
3855 } else if (p == "solo-control-is-listen-control") {
3856 solo_control_mode_changed ();
3857 } else if (p == "solo-mute-gain") {
3858 _solo_cut_control->Changed();
3859 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3860 last_timecode_valid = false;
3861 } else if (p == "playback-buffer-seconds") {
3862 AudioSource::allocate_working_buffers (frame_rate());
3863 } else if (p == "ltc-source-port") {
3864 reconnect_ltc_input ();
3865 } else if (p == "ltc-sink-port") {
3866 reconnect_ltc_output ();
3867 } else if (p == "timecode-generator-offset") {
3868 ltc_tx_parse_offset();
3869 } else if (p == "auto-return-target-list") {
3870 follow_playhead_priority ();
3877 Session::set_history_depth (uint32_t d)
3879 _history.set_depth (d);
3883 Session::load_diskstreams_2X (XMLNode const & node, int)
3886 XMLNodeConstIterator citer;
3888 clist = node.children();
3890 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3893 /* diskstreams added automatically by DiskstreamCreated handler */
3894 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3895 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3896 _diskstreams_2X.push_back (dsp);
3898 error << _("Session: unknown diskstream type in XML") << endmsg;
3902 catch (failed_constructor& err) {
3903 error << _("Session: could not load diskstream via XML state") << endmsg;
3911 /** Connect things to the MMC object */
3913 Session::setup_midi_machine_control ()
3915 _mmc = new MIDI::MachineControl;
3917 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
3918 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
3920 if (!async_out || !async_out) {
3924 /* XXXX argh, passing raw pointers back into libmidi++ */
3926 MIDI::Port* mmc_in = async_in.get();
3927 MIDI::Port* mmc_out = async_out.get();
3929 _mmc->set_ports (mmc_in, mmc_out);
3931 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3932 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3933 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3934 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3935 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3936 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3937 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3938 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3939 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3940 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3941 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3942 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3943 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3945 /* also handle MIDI SPP because its so common */
3947 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3948 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3949 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3952 boost::shared_ptr<Controllable>
3953 Session::solo_cut_control() const
3955 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3956 controls in Ardour that currently get presented to the user in the GUI that require
3957 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3959 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3960 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3964 return _solo_cut_control;
3968 Session::save_snapshot_name (const std::string & n)
3970 /* assure Stateful::_instant_xml is loaded
3971 * add_instant_xml() only adds to existing data and defaults
3972 * to use an empty Tree otherwise
3974 instant_xml ("LastUsedSnapshot");
3976 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
3977 last_used_snapshot->add_property ("name", string(n));
3978 add_instant_xml (*last_used_snapshot, false);
3982 Session::set_snapshot_name (const std::string & n)
3984 _current_snapshot_name = n;
3985 save_snapshot_name (n);
3989 Session::rename (const std::string& new_name)
3991 string legal_name = legalize_for_path (new_name);
3997 string const old_sources_root = _session_dir->sources_root();
3999 if (!_writable || (_state_of_the_state & CannotSave)) {
4000 error << _("Cannot rename read-only session.") << endmsg;
4001 return 0; // don't show "messed up" warning
4003 if (record_status() == Recording) {
4004 error << _("Cannot rename session while recording") << endmsg;
4005 return 0; // don't show "messed up" warning
4008 StateProtector stp (this);
4013 * interchange subdirectory
4017 * Backup files are left unchanged and not renamed.
4020 /* Windows requires that we close all files before attempting the
4021 * rename. This works on other platforms, but isn't necessary there.
4022 * Leave it in place for all platforms though, since it may help
4023 * catch issues that could arise if the way Source files work ever
4024 * change (since most developers are not using Windows).
4027 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4028 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4034 /* pass one: not 100% safe check that the new directory names don't
4038 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4042 /* this is a stupid hack because Glib::path_get_dirname() is
4043 * lexical-only, and so passing it /a/b/c/ gives a different
4044 * result than passing it /a/b/c ...
4047 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4048 oldstr = oldstr.substr (0, oldstr.length() - 1);
4051 string base = Glib::path_get_dirname (oldstr);
4053 newstr = Glib::build_filename (base, legal_name);
4055 cerr << "Looking for " << newstr << endl;
4057 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4058 cerr << " exists\n";
4067 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4073 /* this is a stupid hack because Glib::path_get_dirname() is
4074 * lexical-only, and so passing it /a/b/c/ gives a different
4075 * result than passing it /a/b/c ...
4078 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4079 oldstr = oldstr.substr (0, oldstr.length() - 1);
4082 string base = Glib::path_get_dirname (oldstr);
4083 newstr = Glib::build_filename (base, legal_name);
4085 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4087 cerr << "Rename " << oldstr << " => " << newstr << endl;
4088 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4089 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4090 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4094 /* Reset path in "session dirs" */
4099 /* reset primary SessionDirectory object */
4102 (*_session_dir) = newstr;
4107 /* now rename directory below session_dir/interchange */
4109 string old_interchange_dir;
4110 string new_interchange_dir;
4112 /* use newstr here because we renamed the path
4113 * (folder/directory) that used to be oldstr to newstr above
4116 v.push_back (newstr);
4117 v.push_back (interchange_dir_name);
4118 v.push_back (Glib::path_get_basename (oldstr));
4120 old_interchange_dir = Glib::build_filename (v);
4123 v.push_back (newstr);
4124 v.push_back (interchange_dir_name);
4125 v.push_back (legal_name);
4127 new_interchange_dir = Glib::build_filename (v);
4129 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4131 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4132 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4133 old_interchange_dir, new_interchange_dir,
4136 error << string_compose (_("renaming %s as %2 failed (%3)"),
4137 old_interchange_dir, new_interchange_dir,
4146 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4147 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4149 cerr << "Rename " << oldstr << " => " << newstr << endl;
4151 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4152 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4153 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4159 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4161 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4162 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4164 cerr << "Rename " << oldstr << " => " << newstr << endl;
4166 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4167 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4168 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4173 /* remove old name from recent sessions */
4174 remove_recent_sessions (_path);
4177 /* update file source paths */
4179 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4180 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4182 string p = fs->path ();
4183 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4185 SourceFactory::setup_peakfile(i->second, true);
4189 set_snapshot_name (new_name);
4194 /* save state again to get everything just right */
4196 save_state (_current_snapshot_name);
4198 /* add to recent sessions */
4200 store_recent_sessions (new_name, _path);
4206 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4208 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4212 if (!tree.read (xmlpath)) {
4220 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4223 bool found_sr = false;
4224 bool found_data_format = false;
4226 if (get_session_info_from_path (tree, xmlpath)) {
4232 XMLProperty const * prop;
4233 XMLNode const * root (tree.root());
4235 if ((prop = root->property (X_("sample-rate"))) != 0) {
4236 sample_rate = atoi (prop->value());
4240 const XMLNodeList& children (root->children());
4241 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4242 const XMLNode* child = *c;
4243 if (child->name() == "Config") {
4244 const XMLNodeList& options (child->children());
4245 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4246 XMLNode const * option = *oc;
4247 XMLProperty const * name = option->property("name");
4253 if (name->value() == "native-file-data-format") {
4254 XMLProperty const * value = option->property ("value");
4256 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4258 found_data_format = true;
4264 if (found_data_format) {
4269 return !(found_sr && found_data_format); // zero if they are both found
4273 Session::get_snapshot_from_instant (const std::string& session_dir)
4275 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4277 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4282 if (!tree.read (instant_xml_path)) {
4286 XMLProperty const * prop;
4287 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4288 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4289 return prop->value();
4295 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4296 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4299 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4303 SourcePathMap source_path_map;
4305 boost::shared_ptr<AudioFileSource> afs;
4310 Glib::Threads::Mutex::Lock lm (source_lock);
4312 cerr << " total sources = " << sources.size();
4314 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4315 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4321 if (fs->within_session()) {
4325 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4326 source_path_map[fs->path()].push_back (fs);
4328 SeveralFileSources v;
4330 source_path_map.insert (make_pair (fs->path(), v));
4336 cerr << " fsources = " << total << endl;
4338 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4340 /* tell caller where we are */
4342 string old_path = i->first;
4344 callback (n, total, old_path);
4346 cerr << old_path << endl;
4350 switch (i->second.front()->type()) {
4351 case DataType::AUDIO:
4352 new_path = new_audio_source_path_for_embedded (old_path);
4355 case DataType::MIDI:
4356 /* XXX not implemented yet */
4360 if (new_path.empty()) {
4364 cerr << "Move " << old_path << " => " << new_path << endl;
4366 if (!copy_file (old_path, new_path)) {
4367 cerr << "failed !\n";
4371 /* make sure we stop looking in the external
4372 dir/folder. Remember, this is an all-or-nothing
4373 operations, it doesn't merge just some files.
4375 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4377 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4378 (*f)->set_path (new_path);
4383 save_state ("", false, false);
4389 bool accept_all_files (string const &, void *)
4395 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4397 /* 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.
4402 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4404 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4406 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4408 v.push_back (new_session_folder); /* full path */
4409 v.push_back (interchange_dir_name);
4410 v.push_back (new_session_path); /* just one directory/folder */
4411 v.push_back (typedir);
4412 v.push_back (Glib::path_get_basename (old_path));
4414 return Glib::build_filename (v);
4418 Session::save_as (SaveAs& saveas)
4420 vector<string> files;
4421 string current_folder = Glib::path_get_dirname (_path);
4422 string new_folder = legalize_for_path (saveas.new_name);
4423 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4424 int64_t total_bytes = 0;
4428 int32_t internal_file_cnt = 0;
4430 vector<string> do_not_copy_extensions;
4431 do_not_copy_extensions.push_back (statefile_suffix);
4432 do_not_copy_extensions.push_back (pending_suffix);
4433 do_not_copy_extensions.push_back (backup_suffix);
4434 do_not_copy_extensions.push_back (temp_suffix);
4435 do_not_copy_extensions.push_back (history_suffix);
4437 /* get total size */
4439 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4441 /* need to clear this because
4442 * find_files_matching_filter() is cumulative
4447 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4449 all += files.size();
4451 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4453 g_stat ((*i).c_str(), &gsb);
4454 total_bytes += gsb.st_size;
4458 /* save old values so we can switch back if we are not switching to the new session */
4460 string old_path = _path;
4461 string old_name = _name;
4462 string old_snapshot = _current_snapshot_name;
4463 string old_sd = _session_dir->root_path();
4464 vector<string> old_search_path[DataType::num_types];
4465 string old_config_search_path[DataType::num_types];
4467 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4468 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4469 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4470 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4472 /* switch session directory */
4474 (*_session_dir) = to_dir;
4476 /* create new tree */
4478 if (!_session_dir->create()) {
4479 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4484 /* copy all relevant files. Find each location in session_dirs,
4485 * and copy files from there to target.
4488 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4490 /* need to clear this because
4491 * find_files_matching_filter() is cumulative
4496 const size_t prefix_len = (*sd).path.size();
4498 /* Work just on the files within this session dir */
4500 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4502 /* add dir separator to protect against collisions with
4503 * track names (e.g. track named "audiofiles" or
4507 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4508 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4509 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4511 /* copy all the files. Handling is different for media files
4512 than others because of the *silly* subtree we have below the interchange
4513 folder. That really was a bad idea, but I'm not fixing it as part of
4514 implementing ::save_as().
4517 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4519 std::string from = *i;
4522 string filename = Glib::path_get_basename (from);
4523 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4524 if (filename == ".DS_STORE") {
4529 if (from.find (audiofile_dir_string) != string::npos) {
4531 /* audio file: only copy if asked */
4533 if (saveas.include_media && saveas.copy_media) {
4535 string to = make_new_media_path (*i, to_dir, new_folder);
4537 info << "media file copying from " << from << " to " << to << endmsg;
4539 if (!copy_file (from, to)) {
4540 throw Glib::FileError (Glib::FileError::IO_ERROR,
4541 string_compose(_("\ncopying \"%1\" failed !"), from));
4545 /* we found media files inside the session folder */
4547 internal_file_cnt++;
4549 } else if (from.find (midifile_dir_string) != string::npos) {
4551 /* midi file: always copy unless
4552 * creating an empty new session
4555 if (saveas.include_media) {
4557 string to = make_new_media_path (*i, to_dir, new_folder);
4559 info << "media file copying from " << from << " to " << to << endmsg;
4561 if (!copy_file (from, to)) {
4562 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4566 /* we found media files inside the session folder */
4568 internal_file_cnt++;
4570 } else if (from.find (analysis_dir_string) != string::npos) {
4572 /* make sure analysis dir exists in
4573 * new session folder, but we're not
4574 * copying analysis files here, see
4578 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4583 /* normal non-media file. Don't copy state, history, etc.
4586 bool do_copy = true;
4588 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4589 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4590 /* end of filename matches extension, do not copy file */
4596 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4597 /* don't copy peakfiles if
4598 * we're not copying media
4604 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4606 info << "attempting to make directory/folder " << to << endmsg;
4608 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4609 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4612 info << "attempting to copy " << from << " to " << to << endmsg;
4614 if (!copy_file (from, to)) {
4615 throw Glib::FileError (Glib::FileError::IO_ERROR,
4616 string_compose(_("\ncopying \"%1\" failed !"), from));
4621 /* measure file size even if we're not going to copy so that our Progress
4622 signals are correct, since we included these do-not-copy files
4623 in the computation of the total size and file count.
4627 g_stat (from.c_str(), &gsb);
4628 copied += gsb.st_size;
4631 double fraction = (double) copied / total_bytes;
4633 bool keep_going = true;
4635 if (saveas.copy_media) {
4637 /* no need or expectation of this if
4638 * media is not being copied, because
4639 * it will be fast(ish).
4642 /* tell someone "X percent, file M of N"; M is one-based */
4644 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4652 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4658 /* copy optional folders, if any */
4660 string old = plugins_dir ();
4661 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4662 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4663 copy_files (old, newdir);
4666 old = externals_dir ();
4667 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4668 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4669 copy_files (old, newdir);
4672 old = automation_dir ();
4673 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4674 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4675 copy_files (old, newdir);
4678 if (saveas.include_media) {
4680 if (saveas.copy_media) {
4681 #ifndef PLATFORM_WINDOWS
4682 /* There are problems with analysis files on
4683 * Windows, because they used a colon in their
4684 * names as late as 4.0. Colons are not legal
4685 * under Windows even if NTFS allows them.
4687 * This is a tricky problem to solve so for
4688 * just don't copy these files. They will be
4689 * regenerated as-needed anyway, subject to the
4690 * existing issue that the filenames will be
4691 * rejected by Windows, which is a separate
4692 * problem (though related).
4695 /* only needed if we are copying media, since the
4696 * analysis data refers to media data
4699 old = analysis_dir ();
4700 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4701 string newdir = Glib::build_filename (to_dir, "analysis");
4702 copy_files (old, newdir);
4704 #endif /* PLATFORM_WINDOWS */
4710 set_snapshot_name (saveas.new_name);
4711 _name = saveas.new_name;
4713 if (saveas.include_media && !saveas.copy_media) {
4715 /* reset search paths of the new session (which we're pretending to be right now) to
4716 include the original session search path, so we can still find all audio.
4719 if (internal_file_cnt) {
4720 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4721 ensure_search_path_includes (*s, DataType::AUDIO);
4722 cerr << "be sure to include " << *s << " for audio" << endl;
4725 /* we do not do this for MIDI because we copy
4726 all MIDI files if saveas.include_media is
4732 bool was_dirty = dirty ();
4734 save_state ("", false, false, !saveas.include_media);
4735 save_default_options ();
4737 if (saveas.copy_media && saveas.copy_external) {
4738 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4739 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4743 saveas.final_session_folder_name = _path;
4745 store_recent_sessions (_name, _path);
4747 if (!saveas.switch_to) {
4749 /* switch back to the way things were */
4753 set_snapshot_name (old_snapshot);
4755 (*_session_dir) = old_sd;
4761 if (internal_file_cnt) {
4762 /* reset these to their original values */
4763 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4764 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4769 /* prune session dirs, and update disk space statistics
4774 session_dirs.clear ();
4775 session_dirs.push_back (sp);
4776 refresh_disk_space ();
4778 /* ensure that all existing tracks reset their current capture source paths
4780 reset_write_sources (true, true);
4782 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4783 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4786 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4787 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4793 if (fs->within_session()) {
4794 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4795 fs->set_path (newpath);
4800 } catch (Glib::FileError& e) {
4802 saveas.failure_message = e.what();
4804 /* recursively remove all the directories */
4806 remove_directory (to_dir);
4814 saveas.failure_message = _("unknown reason");
4816 /* recursively remove all the directories */
4818 remove_directory (to_dir);