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 node->add_child_nocopy (_vca_manager->get_state());
1218 child = node->add_child ("Routes");
1220 boost::shared_ptr<RouteList> r = routes.reader ();
1222 RoutePublicOrderSorter cmp;
1223 RouteList public_order (*r);
1224 public_order.sort (cmp);
1226 /* the sort should have put control outs first */
1229 assert (_monitor_out == public_order.front());
1232 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1233 if (!(*i)->is_auditioner()) {
1235 child->add_child_nocopy ((*i)->get_state());
1237 child->add_child_nocopy ((*i)->get_template());
1243 playlists->add_state (node, full_state);
1245 child = node->add_child ("RouteGroups");
1246 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1247 child->add_child_nocopy ((*i)->get_state());
1251 XMLNode* gain_child = node->add_child ("Click");
1252 gain_child->add_child_nocopy (_click_io->state (full_state));
1253 gain_child->add_child_nocopy (_click_gain->state (full_state));
1257 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1258 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1262 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1263 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1266 node->add_child_nocopy (_speakers->get_state());
1267 node->add_child_nocopy (_tempo_map->get_state());
1268 node->add_child_nocopy (get_control_protocol_state());
1271 node->add_child_copy (*_extra_xml);
1275 Glib::Threads::Mutex::Lock lm (lua_lock);
1278 luabridge::LuaRef savedstate ((*_lua_save)());
1279 saved = savedstate.cast<std::string>();
1281 lua.collect_garbage ();
1284 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1285 std::string b64s (b64);
1288 XMLNode* script_node = new XMLNode (X_("Script"));
1289 script_node->add_property (X_("lua"), LUA_VERSION);
1290 script_node->add_content (b64s);
1291 node->add_child_nocopy (*script_node);
1298 Session::get_control_protocol_state ()
1300 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1301 return cpm.get_state();
1305 Session::set_state (const XMLNode& node, int version)
1310 XMLProperty const * prop;
1313 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1315 if (node.name() != X_("Session")) {
1316 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1320 if ((prop = node.property ("name")) != 0) {
1321 _name = prop->value ();
1324 if ((prop = node.property (X_("sample-rate"))) != 0) {
1326 _base_frame_rate = atoi (prop->value());
1327 _nominal_frame_rate = _base_frame_rate;
1329 assert (AudioEngine::instance()->running ());
1330 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1331 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1332 if (r.get_value_or (0)) {
1338 setup_raid_path(_session_dir->root_path());
1340 if ((prop = node.property (X_("id-counter"))) != 0) {
1342 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1343 ID::init_counter (x);
1345 /* old sessions used a timebased counter, so fake
1346 the startup ID counter based on a standard
1351 ID::init_counter (now);
1354 if ((prop = node.property (X_("name-counter"))) != 0) {
1355 init_name_id_counter (atoi (prop->value()));
1358 if ((prop = node.property (X_("event-counter"))) != 0) {
1359 Evoral::init_event_id_counter (atoi (prop->value()));
1362 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1363 _midi_ports->set_midi_port_states (child->children());
1366 IO::disable_connecting ();
1368 Stateful::save_extra_xml (node);
1370 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1371 load_options (*child);
1372 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1373 load_options (*child);
1375 error << _("Session: XML state has no options section") << endmsg;
1378 if (version >= 3000) {
1379 if ((child = find_named_node (node, "Metadata")) == 0) {
1380 warning << _("Session: XML state has no metadata section") << endmsg;
1381 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1386 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1387 _speakers->set_state (*child, version);
1390 if ((child = find_named_node (node, "Sources")) == 0) {
1391 error << _("Session: XML state has no sources section") << endmsg;
1393 } else if (load_sources (*child)) {
1397 if ((child = find_named_node (node, "TempoMap")) == 0) {
1398 error << _("Session: XML state has no Tempo Map section") << endmsg;
1400 } else if (_tempo_map->set_state (*child, version)) {
1404 if ((child = find_named_node (node, "Locations")) == 0) {
1405 error << _("Session: XML state has no locations section") << endmsg;
1407 } else if (_locations->set_state (*child, version)) {
1411 locations_changed ();
1413 if (_session_range_location) {
1414 AudioFileSource::set_header_position_offset (_session_range_location->start());
1417 if ((child = find_named_node (node, "Regions")) == 0) {
1418 error << _("Session: XML state has no Regions section") << endmsg;
1420 } else if (load_regions (*child)) {
1424 if ((child = find_named_node (node, "Playlists")) == 0) {
1425 error << _("Session: XML state has no playlists section") << endmsg;
1427 } else if (playlists->load (*this, *child)) {
1431 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1433 } else if (playlists->load_unused (*this, *child)) {
1437 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1438 if (load_compounds (*child)) {
1443 if (version >= 3000) {
1444 if ((child = find_named_node (node, "Bundles")) == 0) {
1445 warning << _("Session: XML state has no bundles section") << endmsg;
1448 /* We can't load Bundles yet as they need to be able
1449 to convert from port names to Port objects, which can't happen until
1451 _bundle_xml_node = new XMLNode (*child);
1455 if (version < 3000) {
1456 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1457 error << _("Session: XML state has no diskstreams section") << endmsg;
1459 } else if (load_diskstreams_2X (*child, version)) {
1464 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1465 _vca_manager->set_state (*child, version);
1468 if ((child = find_named_node (node, "Routes")) == 0) {
1469 error << _("Session: XML state has no routes section") << endmsg;
1471 } else if (load_routes (*child, version)) {
1475 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1476 _diskstreams_2X.clear ();
1478 if (version >= 3000) {
1480 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1481 error << _("Session: XML state has no route groups section") << endmsg;
1483 } else if (load_route_groups (*child, version)) {
1487 } else if (version < 3000) {
1489 if ((child = find_named_node (node, "EditGroups")) == 0) {
1490 error << _("Session: XML state has no edit groups section") << endmsg;
1492 } else if (load_route_groups (*child, version)) {
1496 if ((child = find_named_node (node, "MixGroups")) == 0) {
1497 error << _("Session: XML state has no mix groups section") << endmsg;
1499 } else if (load_route_groups (*child, version)) {
1504 if ((child = find_named_node (node, "Click")) == 0) {
1505 warning << _("Session: XML state has no click section") << endmsg;
1506 } else if (_click_io) {
1507 setup_click_state (&node);
1510 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1511 ControlProtocolManager::instance().set_state (*child, version);
1514 if ((child = find_named_node (node, "Script"))) {
1515 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1516 if (!(*n)->is_content ()) { continue; }
1518 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1520 Glib::Threads::Mutex::Lock lm (lua_lock);
1521 (*_lua_load)(std::string ((const char*)buf, size));
1522 } catch (luabridge::LuaException const& e) {
1523 cerr << "LuaException:" << e.what () << endl;
1529 update_route_record_state ();
1531 /* here beginneth the second phase ... */
1532 set_snapshot_name (_current_snapshot_name);
1534 StateReady (); /* EMIT SIGNAL */
1547 Session::load_routes (const XMLNode& node, int version)
1550 XMLNodeConstIterator niter;
1551 RouteList new_routes;
1553 nlist = node.children();
1557 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1559 boost::shared_ptr<Route> route;
1560 if (version < 3000) {
1561 route = XMLRouteFactory_2X (**niter, version);
1563 route = XMLRouteFactory (**niter, version);
1567 error << _("Session: cannot create Route from XML description.") << endmsg;
1571 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1573 new_routes.push_back (route);
1576 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1578 add_routes (new_routes, false, false, false);
1580 BootMessage (_("Finished adding tracks/busses"));
1585 boost::shared_ptr<Route>
1586 Session::XMLRouteFactory (const XMLNode& node, int version)
1588 boost::shared_ptr<Route> ret;
1590 if (node.name() != "Route") {
1594 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1596 DataType type = DataType::AUDIO;
1597 XMLProperty const * prop = node.property("default-type");
1600 type = DataType (prop->value());
1603 assert (type != DataType::NIL);
1607 boost::shared_ptr<Track> track;
1609 if (type == DataType::AUDIO) {
1610 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1612 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1615 if (track->init()) {
1619 if (track->set_state (node, version)) {
1623 BOOST_MARK_TRACK (track);
1627 enum Route::Flag flags = Route::Flag(0);
1628 XMLProperty const * prop = node.property("flags");
1630 flags = Route::Flag (string_2_enum (prop->value(), flags));
1633 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1635 if (r->init () == 0 && r->set_state (node, version) == 0) {
1636 BOOST_MARK_ROUTE (r);
1644 boost::shared_ptr<Route>
1645 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1647 boost::shared_ptr<Route> ret;
1649 if (node.name() != "Route") {
1653 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1655 ds_prop = node.property (X_("diskstream"));
1658 DataType type = DataType::AUDIO;
1659 XMLProperty const * prop = node.property("default-type");
1662 type = DataType (prop->value());
1665 assert (type != DataType::NIL);
1669 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1670 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1674 if (i == _diskstreams_2X.end()) {
1675 error << _("Could not find diskstream for route") << endmsg;
1676 return boost::shared_ptr<Route> ();
1679 boost::shared_ptr<Track> track;
1681 if (type == DataType::AUDIO) {
1682 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1684 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1687 if (track->init()) {
1691 if (track->set_state (node, version)) {
1695 track->set_diskstream (*i);
1697 BOOST_MARK_TRACK (track);
1701 enum Route::Flag flags = Route::Flag(0);
1702 XMLProperty const * prop = node.property("flags");
1704 flags = Route::Flag (string_2_enum (prop->value(), flags));
1707 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1709 if (r->init () == 0 && r->set_state (node, version) == 0) {
1710 BOOST_MARK_ROUTE (r);
1719 Session::load_regions (const XMLNode& node)
1722 XMLNodeConstIterator niter;
1723 boost::shared_ptr<Region> region;
1725 nlist = node.children();
1729 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1730 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1731 error << _("Session: cannot create Region from XML description.");
1732 XMLProperty const * name = (**niter).property("name");
1735 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1746 Session::load_compounds (const XMLNode& node)
1748 XMLNodeList calist = node.children();
1749 XMLNodeConstIterator caiter;
1750 XMLProperty const * caprop;
1752 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1753 XMLNode* ca = *caiter;
1757 if ((caprop = ca->property (X_("original"))) == 0) {
1760 orig_id = caprop->value();
1762 if ((caprop = ca->property (X_("copy"))) == 0) {
1765 copy_id = caprop->value();
1767 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1768 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1770 if (!orig || !copy) {
1771 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1777 RegionFactory::add_compound_association (orig, copy);
1784 Session::load_nested_sources (const XMLNode& node)
1787 XMLNodeConstIterator niter;
1789 nlist = node.children();
1791 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1792 if ((*niter)->name() == "Source") {
1794 /* it may already exist, so don't recreate it unnecessarily
1797 XMLProperty const * prop = (*niter)->property (X_("id"));
1799 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1803 ID source_id (prop->value());
1805 if (!source_by_id (source_id)) {
1808 SourceFactory::create (*this, **niter, true);
1810 catch (failed_constructor& err) {
1811 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1818 boost::shared_ptr<Region>
1819 Session::XMLRegionFactory (const XMLNode& node, bool full)
1821 XMLProperty const * type = node.property("type");
1825 const XMLNodeList& nlist = node.children();
1827 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1828 XMLNode *child = (*niter);
1829 if (child->name() == "NestedSource") {
1830 load_nested_sources (*child);
1834 if (!type || type->value() == "audio") {
1835 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1836 } else if (type->value() == "midi") {
1837 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1840 } catch (failed_constructor& err) {
1841 return boost::shared_ptr<Region> ();
1844 return boost::shared_ptr<Region> ();
1847 boost::shared_ptr<AudioRegion>
1848 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1850 XMLProperty const * prop;
1851 boost::shared_ptr<Source> source;
1852 boost::shared_ptr<AudioSource> as;
1854 SourceList master_sources;
1855 uint32_t nchans = 1;
1858 if (node.name() != X_("Region")) {
1859 return boost::shared_ptr<AudioRegion>();
1862 if ((prop = node.property (X_("channels"))) != 0) {
1863 nchans = atoi (prop->value().c_str());
1866 if ((prop = node.property ("name")) == 0) {
1867 cerr << "no name for this region\n";
1871 if ((prop = node.property (X_("source-0"))) == 0) {
1872 if ((prop = node.property ("source")) == 0) {
1873 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1874 return boost::shared_ptr<AudioRegion>();
1878 PBD::ID s_id (prop->value());
1880 if ((source = source_by_id (s_id)) == 0) {
1881 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1882 return boost::shared_ptr<AudioRegion>();
1885 as = boost::dynamic_pointer_cast<AudioSource>(source);
1887 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1888 return boost::shared_ptr<AudioRegion>();
1891 sources.push_back (as);
1893 /* pickup other channels */
1895 for (uint32_t n=1; n < nchans; ++n) {
1896 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1897 if ((prop = node.property (buf)) != 0) {
1899 PBD::ID id2 (prop->value());
1901 if ((source = source_by_id (id2)) == 0) {
1902 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1903 return boost::shared_ptr<AudioRegion>();
1906 as = boost::dynamic_pointer_cast<AudioSource>(source);
1908 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1909 return boost::shared_ptr<AudioRegion>();
1911 sources.push_back (as);
1915 for (uint32_t n = 0; n < nchans; ++n) {
1916 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1917 if ((prop = node.property (buf)) != 0) {
1919 PBD::ID id2 (prop->value());
1921 if ((source = source_by_id (id2)) == 0) {
1922 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1923 return boost::shared_ptr<AudioRegion>();
1926 as = boost::dynamic_pointer_cast<AudioSource>(source);
1928 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1929 return boost::shared_ptr<AudioRegion>();
1931 master_sources.push_back (as);
1936 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1938 /* a final detail: this is the one and only place that we know how long missing files are */
1940 if (region->whole_file()) {
1941 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1942 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1944 sfp->set_length (region->length());
1949 if (!master_sources.empty()) {
1950 if (master_sources.size() != nchans) {
1951 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1953 region->set_master_sources (master_sources);
1961 catch (failed_constructor& err) {
1962 return boost::shared_ptr<AudioRegion>();
1966 boost::shared_ptr<MidiRegion>
1967 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1969 XMLProperty const * prop;
1970 boost::shared_ptr<Source> source;
1971 boost::shared_ptr<MidiSource> ms;
1974 if (node.name() != X_("Region")) {
1975 return boost::shared_ptr<MidiRegion>();
1978 if ((prop = node.property ("name")) == 0) {
1979 cerr << "no name for this region\n";
1983 if ((prop = node.property (X_("source-0"))) == 0) {
1984 if ((prop = node.property ("source")) == 0) {
1985 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1986 return boost::shared_ptr<MidiRegion>();
1990 PBD::ID s_id (prop->value());
1992 if ((source = source_by_id (s_id)) == 0) {
1993 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1994 return boost::shared_ptr<MidiRegion>();
1997 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1999 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2000 return boost::shared_ptr<MidiRegion>();
2003 sources.push_back (ms);
2006 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2007 /* a final detail: this is the one and only place that we know how long missing files are */
2009 if (region->whole_file()) {
2010 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2011 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2013 sfp->set_length (region->length());
2021 catch (failed_constructor& err) {
2022 return boost::shared_ptr<MidiRegion>();
2027 Session::get_sources_as_xml ()
2030 XMLNode* node = new XMLNode (X_("Sources"));
2031 Glib::Threads::Mutex::Lock lm (source_lock);
2033 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2034 node->add_child_nocopy (i->second->get_state());
2041 Session::reset_write_sources (bool mark_write_complete, bool force)
2043 boost::shared_ptr<RouteList> rl = routes.reader();
2044 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2045 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2047 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2048 tr->reset_write_sources(mark_write_complete, force);
2049 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2055 Session::load_sources (const XMLNode& node)
2058 XMLNodeConstIterator niter;
2059 boost::shared_ptr<Source> source; /* don't need this but it stops some
2060 * versions of gcc complaining about
2061 * discarded return values.
2064 nlist = node.children();
2068 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2071 if ((source = XMLSourceFactory (**niter)) == 0) {
2072 error << _("Session: cannot create Source from XML description.") << endmsg;
2075 } catch (MissingSource& err) {
2079 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2080 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2081 PROGRAM_NAME) << endmsg;
2085 if (!no_questions_about_missing_files) {
2086 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2091 switch (user_choice) {
2093 /* user added a new search location, so try again */
2098 /* user asked to quit the entire session load
2103 no_questions_about_missing_files = true;
2107 no_questions_about_missing_files = true;
2114 case DataType::AUDIO:
2115 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2118 case DataType::MIDI:
2119 /* The MIDI file is actually missing so
2120 * just create a new one in the same
2121 * location. Do not announce its
2125 if (!Glib::path_is_absolute (err.path)) {
2126 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2128 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2133 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2134 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2135 /* reset ID to match the missing one */
2136 source->set_id (**niter);
2137 /* Now we can announce it */
2138 SourceFactory::SourceCreated (source);
2149 boost::shared_ptr<Source>
2150 Session::XMLSourceFactory (const XMLNode& node)
2152 if (node.name() != "Source") {
2153 return boost::shared_ptr<Source>();
2157 /* note: do peak building in another thread when loading session state */
2158 return SourceFactory::create (*this, node, true);
2161 catch (failed_constructor& err) {
2162 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2163 return boost::shared_ptr<Source>();
2168 Session::save_template (string template_name, bool replace_existing)
2170 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2174 bool absolute_path = Glib::path_is_absolute (template_name);
2176 /* directory to put the template in */
2177 std::string template_dir_path;
2179 if (!absolute_path) {
2180 std::string user_template_dir(user_template_directory());
2182 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2183 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2184 user_template_dir, g_strerror (errno)) << endmsg;
2188 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2190 template_dir_path = template_name;
2193 if (!ARDOUR::Profile->get_trx()) {
2194 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2195 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2196 template_dir_path) << endmsg;
2200 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2201 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2202 template_dir_path, g_strerror (errno)) << endmsg;
2208 std::string template_file_path;
2210 if (ARDOUR::Profile->get_trx()) {
2211 template_file_path = template_name;
2213 if (absolute_path) {
2214 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2216 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2220 SessionSaveUnderway (); /* EMIT SIGNAL */
2225 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2226 tree.set_root (&get_template());
2229 if (!tree.write (template_file_path)) {
2230 error << _("template not saved") << endmsg;
2234 store_recent_templates (template_file_path);
2240 Session::refresh_disk_space ()
2242 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2244 Glib::Threads::Mutex::Lock lm (space_lock);
2246 /* get freespace on every FS that is part of the session path */
2248 _total_free_4k_blocks = 0;
2249 _total_free_4k_blocks_uncertain = false;
2251 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2253 struct statfs statfsbuf;
2254 statfs (i->path.c_str(), &statfsbuf);
2256 double const scale = statfsbuf.f_bsize / 4096.0;
2258 /* See if this filesystem is read-only */
2259 struct statvfs statvfsbuf;
2260 statvfs (i->path.c_str(), &statvfsbuf);
2262 /* f_bavail can be 0 if it is undefined for whatever
2263 filesystem we are looking at; Samba shares mounted
2264 via GVFS are an example of this.
2266 if (statfsbuf.f_bavail == 0) {
2267 /* block count unknown */
2269 i->blocks_unknown = true;
2270 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2271 /* read-only filesystem */
2273 i->blocks_unknown = false;
2275 /* read/write filesystem with known space */
2276 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2277 i->blocks_unknown = false;
2280 _total_free_4k_blocks += i->blocks;
2281 if (i->blocks_unknown) {
2282 _total_free_4k_blocks_uncertain = true;
2285 #elif defined PLATFORM_WINDOWS
2286 vector<string> scanned_volumes;
2287 vector<string>::iterator j;
2288 vector<space_and_path>::iterator i;
2289 DWORD nSectorsPerCluster, nBytesPerSector,
2290 nFreeClusters, nTotalClusters;
2294 _total_free_4k_blocks = 0;
2296 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2297 strncpy (disk_drive, (*i).path.c_str(), 3);
2301 volume_found = false;
2302 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2304 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2305 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2306 i->blocks = (uint32_t)(nFreeBytes / 4096);
2308 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2309 if (0 == j->compare(disk_drive)) {
2310 volume_found = true;
2315 if (!volume_found) {
2316 scanned_volumes.push_back(disk_drive);
2317 _total_free_4k_blocks += i->blocks;
2322 if (0 == _total_free_4k_blocks) {
2323 strncpy (disk_drive, path().c_str(), 3);
2326 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2328 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2329 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2330 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2337 Session::get_best_session_directory_for_new_audio ()
2339 vector<space_and_path>::iterator i;
2340 string result = _session_dir->root_path();
2342 /* handle common case without system calls */
2344 if (session_dirs.size() == 1) {
2348 /* OK, here's the algorithm we're following here:
2350 We want to select which directory to use for
2351 the next file source to be created. Ideally,
2352 we'd like to use a round-robin process so as to
2353 get maximum performance benefits from splitting
2354 the files across multiple disks.
2356 However, in situations without much diskspace, an
2357 RR approach may end up filling up a filesystem
2358 with new files while others still have space.
2359 Its therefore important to pay some attention to
2360 the freespace in the filesystem holding each
2361 directory as well. However, if we did that by
2362 itself, we'd keep creating new files in the file
2363 system with the most space until it was as full
2364 as all others, thus negating any performance
2365 benefits of this RAID-1 like approach.
2367 So, we use a user-configurable space threshold. If
2368 there are at least 2 filesystems with more than this
2369 much space available, we use RR selection between them.
2370 If not, then we pick the filesystem with the most space.
2372 This gets a good balance between the two
2376 refresh_disk_space ();
2378 int free_enough = 0;
2380 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2381 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2386 if (free_enough >= 2) {
2387 /* use RR selection process, ensuring that the one
2391 i = last_rr_session_dir;
2394 if (++i == session_dirs.end()) {
2395 i = session_dirs.begin();
2398 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2399 SessionDirectory sdir(i->path);
2400 if (sdir.create ()) {
2402 last_rr_session_dir = i;
2407 } while (i != last_rr_session_dir);
2411 /* pick FS with the most freespace (and that
2412 seems to actually work ...)
2415 vector<space_and_path> sorted;
2416 space_and_path_ascending_cmp cmp;
2418 sorted = session_dirs;
2419 sort (sorted.begin(), sorted.end(), cmp);
2421 for (i = sorted.begin(); i != sorted.end(); ++i) {
2422 SessionDirectory sdir(i->path);
2423 if (sdir.create ()) {
2425 last_rr_session_dir = i;
2435 Session::automation_dir () const
2437 return Glib::build_filename (_path, automation_dir_name);
2441 Session::analysis_dir () const
2443 return Glib::build_filename (_path, analysis_dir_name);
2447 Session::plugins_dir () const
2449 return Glib::build_filename (_path, plugins_dir_name);
2453 Session::externals_dir () const
2455 return Glib::build_filename (_path, externals_dir_name);
2459 Session::load_bundles (XMLNode const & node)
2461 XMLNodeList nlist = node.children();
2462 XMLNodeConstIterator niter;
2466 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2467 if ((*niter)->name() == "InputBundle") {
2468 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2469 } else if ((*niter)->name() == "OutputBundle") {
2470 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2472 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2481 Session::load_route_groups (const XMLNode& node, int version)
2483 XMLNodeList nlist = node.children();
2484 XMLNodeConstIterator niter;
2488 if (version >= 3000) {
2490 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2491 if ((*niter)->name() == "RouteGroup") {
2492 RouteGroup* rg = new RouteGroup (*this, "");
2493 add_route_group (rg);
2494 rg->set_state (**niter, version);
2498 } else if (version < 3000) {
2500 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2501 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2502 RouteGroup* rg = new RouteGroup (*this, "");
2503 add_route_group (rg);
2504 rg->set_state (**niter, version);
2513 state_file_filter (const string &str, void* /*arg*/)
2515 return (str.length() > strlen(statefile_suffix) &&
2516 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2520 remove_end(string state)
2522 string statename(state);
2524 string::size_type start,end;
2525 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2526 statename = statename.substr (start+1);
2529 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2530 end = statename.length();
2533 return string(statename.substr (0, end));
2537 Session::possible_states (string path)
2539 vector<string> states;
2540 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2542 transform(states.begin(), states.end(), states.begin(), remove_end);
2544 sort (states.begin(), states.end());
2550 Session::possible_states () const
2552 return possible_states(_path);
2556 Session::add_route_group (RouteGroup* g)
2558 _route_groups.push_back (g);
2559 route_group_added (g); /* EMIT SIGNAL */
2561 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2562 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2563 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2569 Session::remove_route_group (RouteGroup& rg)
2571 list<RouteGroup*>::iterator i;
2573 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2574 _route_groups.erase (i);
2577 route_group_removed (); /* EMIT SIGNAL */
2581 /** Set a new order for our route groups, without adding or removing any.
2582 * @param groups Route group list in the new order.
2585 Session::reorder_route_groups (list<RouteGroup*> groups)
2587 _route_groups = groups;
2589 route_groups_reordered (); /* EMIT SIGNAL */
2595 Session::route_group_by_name (string name)
2597 list<RouteGroup *>::iterator i;
2599 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2600 if ((*i)->name() == name) {
2608 Session::all_route_group() const
2610 return *_all_route_group;
2614 Session::add_commands (vector<Command*> const & cmds)
2616 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2622 Session::add_command (Command* const cmd)
2624 assert (_current_trans);
2625 DEBUG_UNDO_HISTORY (
2626 string_compose ("Current Undo Transaction %1, adding command: %2",
2627 _current_trans->name (),
2629 _current_trans->add_command (cmd);
2632 PBD::StatefulDiffCommand*
2633 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2635 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2641 Session::begin_reversible_command (const string& name)
2643 begin_reversible_command (g_quark_from_string (name.c_str ()));
2646 /** Begin a reversible command using a GQuark to identify it.
2647 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2648 * but there must be as many begin...()s as there are commit...()s.
2651 Session::begin_reversible_command (GQuark q)
2653 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2654 to hold all the commands that are committed. This keeps the order of
2655 commands correct in the history.
2658 if (_current_trans == 0) {
2659 DEBUG_UNDO_HISTORY (string_compose (
2660 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2662 /* start a new transaction */
2663 assert (_current_trans_quarks.empty ());
2664 _current_trans = new UndoTransaction();
2665 _current_trans->set_name (g_quark_to_string (q));
2667 DEBUG_UNDO_HISTORY (
2668 string_compose ("Begin Reversible Command, current transaction: %1",
2669 _current_trans->name ()));
2672 _current_trans_quarks.push_front (q);
2676 Session::abort_reversible_command ()
2678 if (_current_trans != 0) {
2679 DEBUG_UNDO_HISTORY (
2680 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2681 _current_trans->clear();
2682 delete _current_trans;
2684 _current_trans_quarks.clear();
2689 Session::commit_reversible_command (Command *cmd)
2691 assert (_current_trans);
2692 assert (!_current_trans_quarks.empty ());
2697 DEBUG_UNDO_HISTORY (
2698 string_compose ("Current Undo Transaction %1, adding command: %2",
2699 _current_trans->name (),
2701 _current_trans->add_command (cmd);
2704 DEBUG_UNDO_HISTORY (
2705 string_compose ("Commit Reversible Command, current transaction: %1",
2706 _current_trans->name ()));
2708 _current_trans_quarks.pop_front ();
2710 if (!_current_trans_quarks.empty ()) {
2711 DEBUG_UNDO_HISTORY (
2712 string_compose ("Commit Reversible Command, transaction is not "
2713 "top-level, current transaction: %1",
2714 _current_trans->name ()));
2715 /* the transaction we're committing is not the top-level one */
2719 if (_current_trans->empty()) {
2720 /* no commands were added to the transaction, so just get rid of it */
2721 DEBUG_UNDO_HISTORY (
2722 string_compose ("Commit Reversible Command, No commands were "
2723 "added to current transaction: %1",
2724 _current_trans->name ()));
2725 delete _current_trans;
2730 gettimeofday (&now, 0);
2731 _current_trans->set_timestamp (now);
2733 _history.add (_current_trans);
2738 accept_all_audio_files (const string& path, void* /*arg*/)
2740 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2744 if (!AudioFileSource::safe_audio_file_extension (path)) {
2752 accept_all_midi_files (const string& path, void* /*arg*/)
2754 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2758 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2759 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2760 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2764 accept_all_state_files (const string& path, void* /*arg*/)
2766 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2770 std::string const statefile_ext (statefile_suffix);
2771 if (path.length() >= statefile_ext.length()) {
2772 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2779 Session::find_all_sources (string path, set<string>& result)
2784 if (!tree.read (path)) {
2788 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2793 XMLNodeConstIterator niter;
2795 nlist = node->children();
2799 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2801 XMLProperty const * prop;
2803 if ((prop = (*niter)->property (X_("type"))) == 0) {
2807 DataType type (prop->value());
2809 if ((prop = (*niter)->property (X_("name"))) == 0) {
2813 if (Glib::path_is_absolute (prop->value())) {
2814 /* external file, ignore */
2822 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2823 result.insert (found_path);
2831 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2833 vector<string> state_files;
2835 string this_snapshot_path;
2841 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2842 ripped = ripped.substr (0, ripped.length() - 1);
2845 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2847 if (state_files.empty()) {
2852 this_snapshot_path = _path;
2853 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2854 this_snapshot_path += statefile_suffix;
2856 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2858 if (exclude_this_snapshot && *i == this_snapshot_path) {
2862 if (find_all_sources (*i, result) < 0) {
2870 struct RegionCounter {
2871 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2872 AudioSourceList::iterator iter;
2873 boost::shared_ptr<Region> region;
2876 RegionCounter() : count (0) {}
2880 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2882 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2883 return r.get_value_or (1);
2887 Session::cleanup_regions ()
2889 bool removed = false;
2890 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2892 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2894 uint32_t used = playlists->region_use_count (i->second);
2896 if (used == 0 && !i->second->automatic ()) {
2897 boost::weak_ptr<Region> w = i->second;
2900 RegionFactory::map_remove (w);
2907 // re-check to remove parent references of compound regions
2908 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2909 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2913 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2914 if (0 == playlists->region_use_count (i->second)) {
2915 boost::weak_ptr<Region> w = i->second;
2917 RegionFactory::map_remove (w);
2924 /* dump the history list */
2931 Session::can_cleanup_peakfiles () const
2933 if (deletion_in_progress()) {
2936 if (!_writable || (_state_of_the_state & CannotSave)) {
2937 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2940 if (record_status() == Recording) {
2941 error << _("Cannot cleanup peak-files while recording") << endmsg;
2948 Session::cleanup_peakfiles ()
2950 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2955 assert (can_cleanup_peakfiles ());
2956 assert (!peaks_cleanup_in_progres());
2958 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
2960 int timeout = 5000; // 5 seconds
2961 while (!SourceFactory::files_with_peaks.empty()) {
2962 Glib::usleep (1000);
2963 if (--timeout < 0) {
2964 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
2965 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2970 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2971 boost::shared_ptr<AudioSource> as;
2972 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2973 as->close_peakfile();
2977 PBD::clear_directory (session_directory().peak_path());
2979 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
2981 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2982 boost::shared_ptr<AudioSource> as;
2983 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
2984 SourceFactory::setup_peakfile(as, true);
2991 Session::cleanup_sources (CleanupReport& rep)
2993 // FIXME: needs adaptation to midi
2995 vector<boost::shared_ptr<Source> > dead_sources;
2998 vector<string> candidates;
2999 vector<string> unused;
3000 set<string> all_sources;
3009 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3011 /* this is mostly for windows which doesn't allow file
3012 * renaming if the file is in use. But we don't special
3013 * case it because we need to know if this causes
3014 * problems, and the easiest way to notice that is to
3015 * keep it in place for all platforms.
3018 request_stop (false);
3020 _butler->wait_until_finished ();
3022 /* consider deleting all unused playlists */
3024 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3029 /* sync the "all regions" property of each playlist with its current state
3032 playlists->sync_all_regions_with_regions ();
3034 /* find all un-used sources */
3039 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3041 SourceMap::iterator tmp;
3046 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3050 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
3051 dead_sources.push_back (i->second);
3052 i->second->drop_references ();
3058 /* build a list of all the possible audio directories for the session */
3060 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3061 SessionDirectory sdir ((*i).path);
3062 asp += sdir.sound_path();
3064 audio_path += asp.to_string();
3067 /* build a list of all the possible midi directories for the session */
3069 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3070 SessionDirectory sdir ((*i).path);
3071 msp += sdir.midi_path();
3073 midi_path += msp.to_string();
3075 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3076 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3078 /* find all sources, but don't use this snapshot because the
3079 state file on disk still references sources we may have already
3083 find_all_sources_across_snapshots (all_sources, true);
3085 /* add our current source list
3088 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3089 boost::shared_ptr<FileSource> fs;
3090 SourceMap::iterator tmp = i;
3093 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
3095 /* this is mostly for windows which doesn't allow file
3096 * renaming if the file is in use. But we don't special
3097 * case it because we need to know if this causes
3098 * problems, and the easiest way to notice that is to
3099 * keep it in place for all platforms.
3104 if (!fs->is_stub()) {
3106 if (playlists->source_use_count (fs) != 0) {
3107 all_sources.insert (fs->path());
3110 /* we might not remove this source from disk, because it may be used
3111 by other snapshots, but its not being used in this version
3112 so lets get rid of it now, along with any representative regions
3116 RegionFactory::remove_regions_using_source (i->second);
3118 // also remove source from all_sources
3120 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
3121 spath = Glib::path_get_basename (*j);
3122 if (spath == i->second->name()) {
3123 all_sources.erase (j);
3136 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3141 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
3143 tmppath1 = canonical_path (spath);
3144 tmppath2 = canonical_path ((*i));
3146 if (tmppath1 == tmppath2) {
3153 unused.push_back (spath);
3157 /* now try to move all unused files into the "dead" directory(ies) */
3159 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3164 /* don't move the file across filesystems, just
3165 stick it in the `dead_dir_name' directory
3166 on whichever filesystem it was already on.
3169 if ((*x).find ("/sounds/") != string::npos) {
3171 /* old school, go up 1 level */
3173 newpath = Glib::path_get_dirname (*x); // "sounds"
3174 newpath = Glib::path_get_dirname (newpath); // "session-name"
3178 /* new school, go up 4 levels */
3180 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3181 newpath = Glib::path_get_dirname (newpath); // "session-name"
3182 newpath = Glib::path_get_dirname (newpath); // "interchange"
3183 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3186 newpath = Glib::build_filename (newpath, dead_dir_name);
3188 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3189 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3193 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3195 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3197 /* the new path already exists, try versioning */
3199 char buf[PATH_MAX+1];
3203 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3206 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3207 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3211 if (version == 999) {
3212 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3216 newpath = newpath_v;
3221 /* it doesn't exist, or we can't read it or something */
3225 g_stat ((*x).c_str(), &statbuf);
3227 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
3228 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
3229 (*x), newpath, strerror (errno))
3234 /* see if there an easy to find peakfile for this file, and remove it.
3237 string base = Glib::path_get_basename (*x);
3238 base += "%A"; /* this is what we add for the channel suffix of all native files,
3239 or for the first channel of embedded files. it will miss
3240 some peakfiles for other channels
3242 string peakpath = construct_peak_filepath (base);
3244 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
3245 if (::g_unlink (peakpath.c_str()) != 0) {
3246 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
3247 peakpath, _path, strerror (errno))
3249 /* try to back out */
3250 ::rename (newpath.c_str(), _path.c_str());
3255 rep.paths.push_back (*x);
3256 rep.space += statbuf.st_size;
3259 /* dump the history list */
3263 /* save state so we don't end up a session file
3264 referring to non-existent sources.
3271 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3277 Session::cleanup_trash_sources (CleanupReport& rep)
3279 // FIXME: needs adaptation for MIDI
3281 vector<space_and_path>::iterator i;
3287 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3289 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3291 clear_directory (dead_dir, &rep.space, &rep.paths);
3298 Session::set_dirty ()
3300 /* never mark session dirty during loading */
3302 if (_state_of_the_state & Loading) {
3306 bool was_dirty = dirty();
3308 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3312 DirtyChanged(); /* EMIT SIGNAL */
3318 Session::set_clean ()
3320 bool was_dirty = dirty();
3322 _state_of_the_state = Clean;
3326 DirtyChanged(); /* EMIT SIGNAL */
3331 Session::set_deletion_in_progress ()
3333 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3337 Session::clear_deletion_in_progress ()
3339 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3343 Session::add_controllable (boost::shared_ptr<Controllable> c)
3345 /* this adds a controllable to the list managed by the Session.
3346 this is a subset of those managed by the Controllable class
3347 itself, and represents the only ones whose state will be saved
3348 as part of the session.
3351 Glib::Threads::Mutex::Lock lm (controllables_lock);
3352 controllables.insert (c);
3355 struct null_deleter { void operator()(void const *) const {} };
3358 Session::remove_controllable (Controllable* c)
3360 if (_state_of_the_state & Deletion) {
3364 Glib::Threads::Mutex::Lock lm (controllables_lock);
3366 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3368 if (x != controllables.end()) {
3369 controllables.erase (x);
3373 boost::shared_ptr<Controllable>
3374 Session::controllable_by_id (const PBD::ID& id)
3376 Glib::Threads::Mutex::Lock lm (controllables_lock);
3378 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3379 if ((*i)->id() == id) {
3384 return boost::shared_ptr<Controllable>();
3387 boost::shared_ptr<Controllable>
3388 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3390 boost::shared_ptr<Controllable> c;
3391 boost::shared_ptr<Route> r;
3393 switch (desc.top_level_type()) {
3394 case ControllableDescriptor::NamedRoute:
3396 std::string str = desc.top_level_name();
3397 if (str == "Master" || str == "master") {
3399 } else if (str == "control" || str == "listen") {
3402 r = route_by_name (desc.top_level_name());
3407 case ControllableDescriptor::RemoteControlID:
3408 r = route_by_remote_id (desc.rid());
3411 case ControllableDescriptor::SelectionCount:
3412 r = route_by_selected_count (desc.selection_id());
3420 switch (desc.subtype()) {
3421 case ControllableDescriptor::Gain:
3422 c = r->gain_control ();
3425 case ControllableDescriptor::Trim:
3426 c = r->trim()->gain_control ();
3429 case ControllableDescriptor::Solo:
3430 c = r->solo_control();
3433 case ControllableDescriptor::Mute:
3434 c = r->mute_control();
3437 case ControllableDescriptor::Recenable:
3439 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3442 c = t->rec_enable_control ();
3447 case ControllableDescriptor::PanDirection:
3448 c = r->pan_azimuth_control();
3451 case ControllableDescriptor::PanWidth:
3452 c = r->pan_width_control();
3455 case ControllableDescriptor::PanElevation:
3456 c = r->pan_elevation_control();
3459 case ControllableDescriptor::Balance:
3460 /* XXX simple pan control */
3463 case ControllableDescriptor::PluginParameter:
3465 uint32_t plugin = desc.target (0);
3466 uint32_t parameter_index = desc.target (1);
3468 /* revert to zero based counting */
3474 if (parameter_index > 0) {
3478 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3481 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3482 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3487 case ControllableDescriptor::SendGain: {
3488 uint32_t send = desc.target (0);
3492 c = r->send_level_controllable (send);
3497 /* relax and return a null pointer */
3505 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3508 Stateful::add_instant_xml (node, _path);
3511 if (write_to_config) {
3512 Config->add_instant_xml (node);
3517 Session::instant_xml (const string& node_name)
3519 return Stateful::instant_xml (node_name, _path);
3523 Session::save_history (string snapshot_name)
3531 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3532 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3536 if (snapshot_name.empty()) {
3537 snapshot_name = _current_snapshot_name;
3540 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3541 const string backup_filename = history_filename + backup_suffix;
3542 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3543 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3545 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3546 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3547 error << _("could not backup old history file, current history not saved") << endmsg;
3552 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3554 if (!tree.write (xml_path))
3556 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3558 if (g_remove (xml_path.c_str()) != 0) {
3559 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3560 xml_path, g_strerror (errno)) << endmsg;
3562 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3563 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3564 backup_path, g_strerror (errno)) << endmsg;
3574 Session::restore_history (string snapshot_name)
3578 if (snapshot_name.empty()) {
3579 snapshot_name = _current_snapshot_name;
3582 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3583 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3585 info << "Loading history from " << xml_path << endmsg;
3587 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3588 info << string_compose (_("%1: no history file \"%2\" for this session."),
3589 _name, xml_path) << endmsg;
3593 if (!tree.read (xml_path)) {
3594 error << string_compose (_("Could not understand session history file \"%1\""),
3595 xml_path) << endmsg;
3602 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3605 UndoTransaction* ut = new UndoTransaction ();
3608 ut->set_name(t->property("name")->value());
3609 stringstream ss(t->property("tv-sec")->value());
3611 ss.str(t->property("tv-usec")->value());
3613 ut->set_timestamp(tv);
3615 for (XMLNodeConstIterator child_it = t->children().begin();
3616 child_it != t->children().end(); child_it++)
3618 XMLNode *n = *child_it;
3621 if (n->name() == "MementoCommand" ||
3622 n->name() == "MementoUndoCommand" ||
3623 n->name() == "MementoRedoCommand") {
3625 if ((c = memento_command_factory(n))) {
3629 } else if (n->name() == "NoteDiffCommand") {
3630 PBD::ID id (n->property("midi-source")->value());
3631 boost::shared_ptr<MidiSource> midi_source =
3632 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3634 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3636 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3639 } else if (n->name() == "SysExDiffCommand") {
3641 PBD::ID id (n->property("midi-source")->value());
3642 boost::shared_ptr<MidiSource> midi_source =
3643 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3645 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3647 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3650 } else if (n->name() == "PatchChangeDiffCommand") {
3652 PBD::ID id (n->property("midi-source")->value());
3653 boost::shared_ptr<MidiSource> midi_source =
3654 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3656 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3658 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3661 } else if (n->name() == "StatefulDiffCommand") {
3662 if ((c = stateful_diff_command_factory (n))) {
3663 ut->add_command (c);
3666 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3677 Session::config_changed (std::string p, bool ours)
3683 if (p == "seamless-loop") {
3685 } else if (p == "rf-speed") {
3687 } else if (p == "auto-loop") {
3689 } else if (p == "auto-input") {
3691 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3692 /* auto-input only makes a difference if we're rolling */
3693 set_track_monitor_input_status (!config.get_auto_input());
3696 } else if (p == "punch-in") {
3700 if ((location = _locations->auto_punch_location()) != 0) {
3702 if (config.get_punch_in ()) {
3703 replace_event (SessionEvent::PunchIn, location->start());
3705 remove_event (location->start(), SessionEvent::PunchIn);
3709 } else if (p == "punch-out") {
3713 if ((location = _locations->auto_punch_location()) != 0) {
3715 if (config.get_punch_out()) {
3716 replace_event (SessionEvent::PunchOut, location->end());
3718 clear_events (SessionEvent::PunchOut);
3722 } else if (p == "edit-mode") {
3724 Glib::Threads::Mutex::Lock lm (playlists->lock);
3726 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3727 (*i)->set_edit_mode (Config->get_edit_mode ());
3730 } else if (p == "use-video-sync") {
3732 waiting_for_sync_offset = config.get_use_video_sync();
3734 } else if (p == "mmc-control") {
3736 //poke_midi_thread ();
3738 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3740 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3742 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3744 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3746 } else if (p == "midi-control") {
3748 //poke_midi_thread ();
3750 } else if (p == "raid-path") {
3752 setup_raid_path (config.get_raid_path());
3754 } else if (p == "timecode-format") {
3758 } else if (p == "video-pullup") {
3762 } else if (p == "seamless-loop") {
3764 if (play_loop && transport_rolling()) {
3765 // to reset diskstreams etc
3766 request_play_loop (true);
3769 } else if (p == "rf-speed") {
3771 cumulative_rf_motion = 0;
3774 } else if (p == "click-sound") {
3776 setup_click_sounds (1);
3778 } else if (p == "click-emphasis-sound") {
3780 setup_click_sounds (-1);
3782 } else if (p == "clicking") {
3784 if (Config->get_clicking()) {
3785 if (_click_io && click_data) { // don't require emphasis data
3792 } else if (p == "click-gain") {
3795 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3798 } else if (p == "send-mtc") {
3800 if (Config->get_send_mtc ()) {
3801 /* mark us ready to send */
3802 next_quarter_frame_to_send = 0;
3805 } else if (p == "send-mmc") {
3807 _mmc->enable_send (Config->get_send_mmc ());
3809 } else if (p == "midi-feedback") {
3811 session_midi_feedback = Config->get_midi_feedback();
3813 } else if (p == "jack-time-master") {
3815 engine().reset_timebase ();
3817 } else if (p == "native-file-header-format") {
3819 if (!first_file_header_format_reset) {
3820 reset_native_file_format ();
3823 first_file_header_format_reset = false;
3825 } else if (p == "native-file-data-format") {
3827 if (!first_file_data_format_reset) {
3828 reset_native_file_format ();
3831 first_file_data_format_reset = false;
3833 } else if (p == "external-sync") {
3834 if (!config.get_external_sync()) {
3835 drop_sync_source ();
3837 switch_to_sync_source (Config->get_sync_source());
3839 } else if (p == "denormal-model") {
3841 } else if (p == "history-depth") {
3842 set_history_depth (Config->get_history_depth());
3843 } else if (p == "remote-model") {
3844 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3847 } else if (p == "initial-program-change") {
3849 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3852 buf[0] = MIDI::program; // channel zero by default
3853 buf[1] = (Config->get_initial_program_change() & 0x7f);
3855 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3857 } else if (p == "solo-mute-override") {
3858 // catch_up_on_solo_mute_override ();
3859 } else if (p == "listen-position" || p == "pfl-position") {
3860 listen_position_changed ();
3861 } else if (p == "solo-control-is-listen-control") {
3862 solo_control_mode_changed ();
3863 } else if (p == "solo-mute-gain") {
3864 _solo_cut_control->Changed();
3865 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3866 last_timecode_valid = false;
3867 } else if (p == "playback-buffer-seconds") {
3868 AudioSource::allocate_working_buffers (frame_rate());
3869 } else if (p == "ltc-source-port") {
3870 reconnect_ltc_input ();
3871 } else if (p == "ltc-sink-port") {
3872 reconnect_ltc_output ();
3873 } else if (p == "timecode-generator-offset") {
3874 ltc_tx_parse_offset();
3875 } else if (p == "auto-return-target-list") {
3876 follow_playhead_priority ();
3883 Session::set_history_depth (uint32_t d)
3885 _history.set_depth (d);
3889 Session::load_diskstreams_2X (XMLNode const & node, int)
3892 XMLNodeConstIterator citer;
3894 clist = node.children();
3896 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3899 /* diskstreams added automatically by DiskstreamCreated handler */
3900 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3901 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3902 _diskstreams_2X.push_back (dsp);
3904 error << _("Session: unknown diskstream type in XML") << endmsg;
3908 catch (failed_constructor& err) {
3909 error << _("Session: could not load diskstream via XML state") << endmsg;
3917 /** Connect things to the MMC object */
3919 Session::setup_midi_machine_control ()
3921 _mmc = new MIDI::MachineControl;
3923 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
3924 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
3926 if (!async_out || !async_out) {
3930 /* XXXX argh, passing raw pointers back into libmidi++ */
3932 MIDI::Port* mmc_in = async_in.get();
3933 MIDI::Port* mmc_out = async_out.get();
3935 _mmc->set_ports (mmc_in, mmc_out);
3937 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3938 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3939 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3940 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3941 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3942 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3943 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3944 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3945 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3946 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3947 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3948 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3949 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3951 /* also handle MIDI SPP because its so common */
3953 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3954 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3955 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3958 boost::shared_ptr<Controllable>
3959 Session::solo_cut_control() const
3961 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3962 controls in Ardour that currently get presented to the user in the GUI that require
3963 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3965 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3966 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3970 return _solo_cut_control;
3974 Session::save_snapshot_name (const std::string & n)
3976 /* assure Stateful::_instant_xml is loaded
3977 * add_instant_xml() only adds to existing data and defaults
3978 * to use an empty Tree otherwise
3980 instant_xml ("LastUsedSnapshot");
3982 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
3983 last_used_snapshot->add_property ("name", string(n));
3984 add_instant_xml (*last_used_snapshot, false);
3988 Session::set_snapshot_name (const std::string & n)
3990 _current_snapshot_name = n;
3991 save_snapshot_name (n);
3995 Session::rename (const std::string& new_name)
3997 string legal_name = legalize_for_path (new_name);
4003 string const old_sources_root = _session_dir->sources_root();
4005 if (!_writable || (_state_of_the_state & CannotSave)) {
4006 error << _("Cannot rename read-only session.") << endmsg;
4007 return 0; // don't show "messed up" warning
4009 if (record_status() == Recording) {
4010 error << _("Cannot rename session while recording") << endmsg;
4011 return 0; // don't show "messed up" warning
4014 StateProtector stp (this);
4019 * interchange subdirectory
4023 * Backup files are left unchanged and not renamed.
4026 /* Windows requires that we close all files before attempting the
4027 * rename. This works on other platforms, but isn't necessary there.
4028 * Leave it in place for all platforms though, since it may help
4029 * catch issues that could arise if the way Source files work ever
4030 * change (since most developers are not using Windows).
4033 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4034 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4040 /* pass one: not 100% safe check that the new directory names don't
4044 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4048 /* this is a stupid hack because Glib::path_get_dirname() is
4049 * lexical-only, and so passing it /a/b/c/ gives a different
4050 * result than passing it /a/b/c ...
4053 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4054 oldstr = oldstr.substr (0, oldstr.length() - 1);
4057 string base = Glib::path_get_dirname (oldstr);
4059 newstr = Glib::build_filename (base, legal_name);
4061 cerr << "Looking for " << newstr << endl;
4063 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4064 cerr << " exists\n";
4073 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4079 /* this is a stupid hack because Glib::path_get_dirname() is
4080 * lexical-only, and so passing it /a/b/c/ gives a different
4081 * result than passing it /a/b/c ...
4084 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4085 oldstr = oldstr.substr (0, oldstr.length() - 1);
4088 string base = Glib::path_get_dirname (oldstr);
4089 newstr = Glib::build_filename (base, legal_name);
4091 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4093 cerr << "Rename " << oldstr << " => " << newstr << endl;
4094 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4095 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4096 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4100 /* Reset path in "session dirs" */
4105 /* reset primary SessionDirectory object */
4108 (*_session_dir) = newstr;
4113 /* now rename directory below session_dir/interchange */
4115 string old_interchange_dir;
4116 string new_interchange_dir;
4118 /* use newstr here because we renamed the path
4119 * (folder/directory) that used to be oldstr to newstr above
4122 v.push_back (newstr);
4123 v.push_back (interchange_dir_name);
4124 v.push_back (Glib::path_get_basename (oldstr));
4126 old_interchange_dir = Glib::build_filename (v);
4129 v.push_back (newstr);
4130 v.push_back (interchange_dir_name);
4131 v.push_back (legal_name);
4133 new_interchange_dir = Glib::build_filename (v);
4135 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4137 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4138 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4139 old_interchange_dir, new_interchange_dir,
4142 error << string_compose (_("renaming %s as %2 failed (%3)"),
4143 old_interchange_dir, new_interchange_dir,
4152 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4153 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4155 cerr << "Rename " << oldstr << " => " << newstr << endl;
4157 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4158 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4159 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4165 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4167 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4168 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4170 cerr << "Rename " << oldstr << " => " << newstr << endl;
4172 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4173 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4174 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4179 /* remove old name from recent sessions */
4180 remove_recent_sessions (_path);
4183 /* update file source paths */
4185 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4186 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4188 string p = fs->path ();
4189 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4191 SourceFactory::setup_peakfile(i->second, true);
4195 set_snapshot_name (new_name);
4200 /* save state again to get everything just right */
4202 save_state (_current_snapshot_name);
4204 /* add to recent sessions */
4206 store_recent_sessions (new_name, _path);
4212 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4214 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4218 if (!tree.read (xmlpath)) {
4226 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4229 bool found_sr = false;
4230 bool found_data_format = false;
4232 if (get_session_info_from_path (tree, xmlpath)) {
4238 XMLProperty const * prop;
4239 XMLNode const * root (tree.root());
4241 if ((prop = root->property (X_("sample-rate"))) != 0) {
4242 sample_rate = atoi (prop->value());
4246 const XMLNodeList& children (root->children());
4247 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4248 const XMLNode* child = *c;
4249 if (child->name() == "Config") {
4250 const XMLNodeList& options (child->children());
4251 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4252 XMLNode const * option = *oc;
4253 XMLProperty const * name = option->property("name");
4259 if (name->value() == "native-file-data-format") {
4260 XMLProperty const * value = option->property ("value");
4262 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4264 found_data_format = true;
4270 if (found_data_format) {
4275 return !(found_sr && found_data_format); // zero if they are both found
4279 Session::get_snapshot_from_instant (const std::string& session_dir)
4281 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4283 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4288 if (!tree.read (instant_xml_path)) {
4292 XMLProperty const * prop;
4293 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4294 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4295 return prop->value();
4301 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4302 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4305 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4309 SourcePathMap source_path_map;
4311 boost::shared_ptr<AudioFileSource> afs;
4316 Glib::Threads::Mutex::Lock lm (source_lock);
4318 cerr << " total sources = " << sources.size();
4320 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4321 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4327 if (fs->within_session()) {
4331 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4332 source_path_map[fs->path()].push_back (fs);
4334 SeveralFileSources v;
4336 source_path_map.insert (make_pair (fs->path(), v));
4342 cerr << " fsources = " << total << endl;
4344 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4346 /* tell caller where we are */
4348 string old_path = i->first;
4350 callback (n, total, old_path);
4352 cerr << old_path << endl;
4356 switch (i->second.front()->type()) {
4357 case DataType::AUDIO:
4358 new_path = new_audio_source_path_for_embedded (old_path);
4361 case DataType::MIDI:
4362 /* XXX not implemented yet */
4366 if (new_path.empty()) {
4370 cerr << "Move " << old_path << " => " << new_path << endl;
4372 if (!copy_file (old_path, new_path)) {
4373 cerr << "failed !\n";
4377 /* make sure we stop looking in the external
4378 dir/folder. Remember, this is an all-or-nothing
4379 operations, it doesn't merge just some files.
4381 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4383 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4384 (*f)->set_path (new_path);
4389 save_state ("", false, false);
4395 bool accept_all_files (string const &, void *)
4401 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4403 /* 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.
4408 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4410 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4412 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4414 v.push_back (new_session_folder); /* full path */
4415 v.push_back (interchange_dir_name);
4416 v.push_back (new_session_path); /* just one directory/folder */
4417 v.push_back (typedir);
4418 v.push_back (Glib::path_get_basename (old_path));
4420 return Glib::build_filename (v);
4424 Session::save_as (SaveAs& saveas)
4426 vector<string> files;
4427 string current_folder = Glib::path_get_dirname (_path);
4428 string new_folder = legalize_for_path (saveas.new_name);
4429 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4430 int64_t total_bytes = 0;
4434 int32_t internal_file_cnt = 0;
4436 vector<string> do_not_copy_extensions;
4437 do_not_copy_extensions.push_back (statefile_suffix);
4438 do_not_copy_extensions.push_back (pending_suffix);
4439 do_not_copy_extensions.push_back (backup_suffix);
4440 do_not_copy_extensions.push_back (temp_suffix);
4441 do_not_copy_extensions.push_back (history_suffix);
4443 /* get total size */
4445 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4447 /* need to clear this because
4448 * find_files_matching_filter() is cumulative
4453 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4455 all += files.size();
4457 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4459 g_stat ((*i).c_str(), &gsb);
4460 total_bytes += gsb.st_size;
4464 /* save old values so we can switch back if we are not switching to the new session */
4466 string old_path = _path;
4467 string old_name = _name;
4468 string old_snapshot = _current_snapshot_name;
4469 string old_sd = _session_dir->root_path();
4470 vector<string> old_search_path[DataType::num_types];
4471 string old_config_search_path[DataType::num_types];
4473 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4474 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4475 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4476 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4478 /* switch session directory */
4480 (*_session_dir) = to_dir;
4482 /* create new tree */
4484 if (!_session_dir->create()) {
4485 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4490 /* copy all relevant files. Find each location in session_dirs,
4491 * and copy files from there to target.
4494 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4496 /* need to clear this because
4497 * find_files_matching_filter() is cumulative
4502 const size_t prefix_len = (*sd).path.size();
4504 /* Work just on the files within this session dir */
4506 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4508 /* add dir separator to protect against collisions with
4509 * track names (e.g. track named "audiofiles" or
4513 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4514 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4515 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4517 /* copy all the files. Handling is different for media files
4518 than others because of the *silly* subtree we have below the interchange
4519 folder. That really was a bad idea, but I'm not fixing it as part of
4520 implementing ::save_as().
4523 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4525 std::string from = *i;
4528 string filename = Glib::path_get_basename (from);
4529 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4530 if (filename == ".DS_STORE") {
4535 if (from.find (audiofile_dir_string) != string::npos) {
4537 /* audio file: only copy if asked */
4539 if (saveas.include_media && saveas.copy_media) {
4541 string to = make_new_media_path (*i, to_dir, new_folder);
4543 info << "media file copying from " << from << " to " << to << endmsg;
4545 if (!copy_file (from, to)) {
4546 throw Glib::FileError (Glib::FileError::IO_ERROR,
4547 string_compose(_("\ncopying \"%1\" failed !"), from));
4551 /* we found media files inside the session folder */
4553 internal_file_cnt++;
4555 } else if (from.find (midifile_dir_string) != string::npos) {
4557 /* midi file: always copy unless
4558 * creating an empty new session
4561 if (saveas.include_media) {
4563 string to = make_new_media_path (*i, to_dir, new_folder);
4565 info << "media file copying from " << from << " to " << to << endmsg;
4567 if (!copy_file (from, to)) {
4568 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4572 /* we found media files inside the session folder */
4574 internal_file_cnt++;
4576 } else if (from.find (analysis_dir_string) != string::npos) {
4578 /* make sure analysis dir exists in
4579 * new session folder, but we're not
4580 * copying analysis files here, see
4584 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4589 /* normal non-media file. Don't copy state, history, etc.
4592 bool do_copy = true;
4594 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4595 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4596 /* end of filename matches extension, do not copy file */
4602 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4603 /* don't copy peakfiles if
4604 * we're not copying media
4610 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4612 info << "attempting to make directory/folder " << to << endmsg;
4614 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4615 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4618 info << "attempting to copy " << from << " to " << to << endmsg;
4620 if (!copy_file (from, to)) {
4621 throw Glib::FileError (Glib::FileError::IO_ERROR,
4622 string_compose(_("\ncopying \"%1\" failed !"), from));
4627 /* measure file size even if we're not going to copy so that our Progress
4628 signals are correct, since we included these do-not-copy files
4629 in the computation of the total size and file count.
4633 g_stat (from.c_str(), &gsb);
4634 copied += gsb.st_size;
4637 double fraction = (double) copied / total_bytes;
4639 bool keep_going = true;
4641 if (saveas.copy_media) {
4643 /* no need or expectation of this if
4644 * media is not being copied, because
4645 * it will be fast(ish).
4648 /* tell someone "X percent, file M of N"; M is one-based */
4650 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4658 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4664 /* copy optional folders, if any */
4666 string old = plugins_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 = externals_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 old = automation_dir ();
4679 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4680 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4681 copy_files (old, newdir);
4684 if (saveas.include_media) {
4686 if (saveas.copy_media) {
4687 #ifndef PLATFORM_WINDOWS
4688 /* There are problems with analysis files on
4689 * Windows, because they used a colon in their
4690 * names as late as 4.0. Colons are not legal
4691 * under Windows even if NTFS allows them.
4693 * This is a tricky problem to solve so for
4694 * just don't copy these files. They will be
4695 * regenerated as-needed anyway, subject to the
4696 * existing issue that the filenames will be
4697 * rejected by Windows, which is a separate
4698 * problem (though related).
4701 /* only needed if we are copying media, since the
4702 * analysis data refers to media data
4705 old = analysis_dir ();
4706 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4707 string newdir = Glib::build_filename (to_dir, "analysis");
4708 copy_files (old, newdir);
4710 #endif /* PLATFORM_WINDOWS */
4716 set_snapshot_name (saveas.new_name);
4717 _name = saveas.new_name;
4719 if (saveas.include_media && !saveas.copy_media) {
4721 /* reset search paths of the new session (which we're pretending to be right now) to
4722 include the original session search path, so we can still find all audio.
4725 if (internal_file_cnt) {
4726 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4727 ensure_search_path_includes (*s, DataType::AUDIO);
4728 cerr << "be sure to include " << *s << " for audio" << endl;
4731 /* we do not do this for MIDI because we copy
4732 all MIDI files if saveas.include_media is
4738 bool was_dirty = dirty ();
4740 save_state ("", false, false, !saveas.include_media);
4741 save_default_options ();
4743 if (saveas.copy_media && saveas.copy_external) {
4744 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4745 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4749 saveas.final_session_folder_name = _path;
4751 store_recent_sessions (_name, _path);
4753 if (!saveas.switch_to) {
4755 /* switch back to the way things were */
4759 set_snapshot_name (old_snapshot);
4761 (*_session_dir) = old_sd;
4767 if (internal_file_cnt) {
4768 /* reset these to their original values */
4769 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4770 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4775 /* prune session dirs, and update disk space statistics
4780 session_dirs.clear ();
4781 session_dirs.push_back (sp);
4782 refresh_disk_space ();
4784 /* ensure that all existing tracks reset their current capture source paths
4786 reset_write_sources (true, true);
4788 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4789 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4792 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4793 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4799 if (fs->within_session()) {
4800 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4801 fs->set_path (newpath);
4806 } catch (Glib::FileError& e) {
4808 saveas.failure_message = e.what();
4810 /* recursively remove all the directories */
4812 remove_directory (to_dir);
4820 saveas.failure_message = _("unknown reason");
4822 /* recursively remove all the directories */
4824 remove_directory (to_dir);