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 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
95 #include "ardour/lv2_plugin.h"
96 #include "ardour/midi_model.h"
97 #include "ardour/midi_patch_manager.h"
98 #include "ardour/midi_region.h"
99 #include "ardour/midi_scene_changer.h"
100 #include "ardour/midi_source.h"
101 #include "ardour/midi_track.h"
102 #include "ardour/pannable.h"
103 #include "ardour/playlist_factory.h"
104 #include "ardour/playlist_source.h"
105 #include "ardour/port.h"
106 #include "ardour/processor.h"
107 #include "ardour/progress.h"
108 #include "ardour/profile.h"
109 #include "ardour/proxy_controllable.h"
110 #include "ardour/recent_sessions.h"
111 #include "ardour/region_factory.h"
112 #include "ardour/revision.h"
113 #include "ardour/route_group.h"
114 #include "ardour/send.h"
115 #include "ardour/session.h"
116 #include "ardour/session_directory.h"
117 #include "ardour/session_metadata.h"
118 #include "ardour/session_playlists.h"
119 #include "ardour/session_state_utils.h"
120 #include "ardour/silentfilesource.h"
121 #include "ardour/sndfilesource.h"
122 #include "ardour/source_factory.h"
123 #include "ardour/speakers.h"
124 #include "ardour/template_utils.h"
125 #include "ardour/tempo.h"
126 #include "ardour/ticker.h"
127 #include "ardour/user_bundle.h"
128 #include "ardour/vca.h"
129 #include "ardour/vca_manager.h"
131 #include "control_protocol/control_protocol.h"
133 #include "LuaBridge/LuaBridge.h"
135 #include "pbd/i18n.h"
139 using namespace ARDOUR;
142 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
145 Session::pre_engine_init (string fullpath)
147 if (fullpath.empty()) {
149 throw failed_constructor();
152 /* discover canonical fullpath */
154 _path = canonical_path(fullpath);
157 if (Profile->get_trx() ) {
158 // Waves TracksLive has a usecase of session replacement with a new one.
159 // We should check session state file (<session_name>.ardour) existance
160 // to determine if the session is new or not
162 string full_session_name = Glib::build_filename( fullpath, _name );
163 full_session_name += statefile_suffix;
165 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
167 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
170 /* finish initialization that can't be done in a normal C++ constructor
174 timerclear (&last_mmc_step);
175 g_atomic_int_set (&processing_prohibited, 0);
176 g_atomic_int_set (&_record_status, Disabled);
177 g_atomic_int_set (&_playback_load, 100);
178 g_atomic_int_set (&_capture_load, 100);
180 _all_route_group->set_active (true, this);
181 interpolation.add_channel_to (0, 0);
183 if (config.get_use_video_sync()) {
184 waiting_for_sync_offset = true;
186 waiting_for_sync_offset = false;
189 last_rr_session_dir = session_dirs.begin();
191 set_history_depth (Config->get_history_depth());
193 /* default: assume simple stereo speaker configuration */
195 _speakers->setup_default_speakers (2);
197 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
198 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
199 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
200 add_controllable (_solo_cut_control);
202 /* These are all static "per-class" signals */
204 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
205 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
206 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
207 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
208 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
210 /* stop IO objects from doing stuff until we're ready for them */
212 Delivery::disable_panners ();
213 IO::disable_connecting ();
217 Session::post_engine_init ()
219 BootMessage (_("Set block size and sample rate"));
221 set_block_size (_engine.samples_per_cycle());
222 set_frame_rate (_engine.sample_rate());
224 BootMessage (_("Using configuration"));
226 _midi_ports = new MidiPortManager;
228 MIDISceneChanger* msc;
230 _scene_changer = msc = new MIDISceneChanger (*this);
231 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
232 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
234 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
235 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
237 setup_midi_machine_control ();
239 if (_butler->start_thread()) {
240 error << _("Butler did not start") << endmsg;
244 if (start_midi_thread ()) {
245 error << _("MIDI I/O thread did not start") << endmsg;
249 setup_click_sounds (0);
250 setup_midi_control ();
252 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
253 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
256 /* tempo map requires sample rate knowledge */
259 _tempo_map = new TempoMap (_current_frame_rate);
260 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
261 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::gui_tempo_map_changed, this));
263 /* MidiClock requires a tempo map */
266 midi_clock = new MidiClockTicker ();
267 midi_clock->set_session (this);
269 /* crossfades require sample rate knowledge */
271 SndFileSource::setup_standard_crossfades (*this, frame_rate());
272 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
274 AudioDiskstream::allocate_working_buffers();
275 refresh_disk_space ();
277 /* we're finally ready to call set_state() ... all objects have
278 * been created, the engine is running.
282 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
283 error << _("Could not set session state from XML") << endmsg;
287 // set_state() will call setup_raid_path(), but if it's a new session we need
288 // to call setup_raid_path() here.
289 setup_raid_path (_path);
294 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
295 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
297 Config->map_parameters (ff);
298 config.map_parameters (ft);
299 _butler->map_parameters ();
301 /* Reset all panners */
303 Delivery::reset_panners ();
305 /* this will cause the CPM to instantiate any protocols that are in use
306 * (or mandatory), which will pass it this Session, and then call
307 * set_state() on each instantiated protocol to match stored state.
310 ControlProtocolManager::instance().set_session (this);
312 /* This must be done after the ControlProtocolManager set_session above,
313 as it will set states for ports which the ControlProtocolManager creates.
316 // XXX set state of MIDI::Port's
317 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
319 /* And this must be done after the MIDI::Manager::set_port_states as
320 * it will try to make connections whose details are loaded by set_port_states.
325 /* Let control protocols know that we are now all connected, so they
326 * could start talking to surfaces if they want to.
329 ControlProtocolManager::instance().midi_connectivity_established ();
331 if (_is_new && !no_auto_connect()) {
332 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
333 auto_connect_master_bus ();
336 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
338 /* update latencies */
340 initialize_latencies ();
342 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
343 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
344 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
346 } catch (AudioEngine::PortRegistrationFailure& err) {
347 /* handle this one in a different way than all others, so that its clear what happened */
348 error << err.what() << endmsg;
350 } catch (std::exception const & e) {
351 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
354 error << _("Unknown exception during session setup") << endmsg;
358 BootMessage (_("Reset Remote Controls"));
360 // send_full_time_code (0);
361 _engine.transport_locate (0);
363 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
364 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
366 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
369 /* initial program change will be delivered later; see ::config_changed() */
371 _state_of_the_state = Clean;
373 Port::set_connecting_blocked (false);
375 DirtyChanged (); /* EMIT SIGNAL */
379 } else if (state_was_pending) {
381 remove_pending_capture_state ();
382 state_was_pending = false;
385 /* Now, finally, we can fill the playback buffers */
387 BootMessage (_("Filling playback buffers"));
389 boost::shared_ptr<RouteList> rl = routes.reader();
390 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
391 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
392 if (trk && !trk->hidden()) {
393 trk->seek (_transport_frame, true);
401 Session::session_loaded ()
405 _state_of_the_state = Clean;
407 DirtyChanged (); /* EMIT SIGNAL */
411 } else if (state_was_pending) {
413 remove_pending_capture_state ();
414 state_was_pending = false;
417 /* Now, finally, we can fill the playback buffers */
419 BootMessage (_("Filling playback buffers"));
420 force_locate (_transport_frame, false);
424 Session::raid_path () const
426 Searchpath raid_search_path;
428 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
429 raid_search_path += (*i).path;
432 return raid_search_path.to_string ();
436 Session::setup_raid_path (string path)
445 session_dirs.clear ();
447 Searchpath search_path(path);
448 Searchpath sound_search_path;
449 Searchpath midi_search_path;
451 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
453 sp.blocks = 0; // not needed
454 session_dirs.push_back (sp);
456 SessionDirectory sdir(sp.path);
458 sound_search_path += sdir.sound_path ();
459 midi_search_path += sdir.midi_path ();
462 // reset the round-robin soundfile path thingie
463 last_rr_session_dir = session_dirs.begin();
467 Session::path_is_within_session (const std::string& path)
469 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
470 if (PBD::path_is_within (i->path, path)) {
478 Session::ensure_subdirs ()
482 dir = session_directory().peak_path();
484 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
485 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
489 dir = session_directory().sound_path();
491 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
492 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
496 dir = session_directory().midi_path();
498 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
499 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
503 dir = session_directory().dead_path();
505 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
506 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
510 dir = session_directory().export_path();
512 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
513 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
517 dir = analysis_dir ();
519 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
520 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
524 dir = plugins_dir ();
526 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
527 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
531 dir = externals_dir ();
533 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
534 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
541 /** @param session_template directory containing session template, or empty.
542 * Caller must not hold process lock.
545 Session::create (const string& session_template, BusProfile* bus_profile)
547 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
548 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
552 if (ensure_subdirs ()) {
556 _writable = exists_and_writable (_path);
558 if (!session_template.empty()) {
559 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
561 FILE* in = g_fopen (in_path.c_str(), "rb");
564 /* no need to call legalize_for_path() since the string
565 * in session_template is already a legal path name
567 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
569 FILE* out = g_fopen (out_path.c_str(), "wb");
573 stringstream new_session;
576 size_t charsRead = fread (buf, sizeof(char), 1024, in);
579 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
584 if (charsRead == 0) {
587 new_session.write (buf, charsRead);
591 string file_contents = new_session.str();
592 size_t writeSize = file_contents.length();
593 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
594 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
602 if (!ARDOUR::Profile->get_trx()) {
603 /* Copy plugin state files from template to new session */
604 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
605 copy_recurse (template_plugins, plugins_dir ());
611 error << string_compose (_("Could not open %1 for writing session template"), out_path)
618 error << string_compose (_("Could not open session template %1 for reading"), in_path)
625 if (Profile->get_trx()) {
627 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
628 Remember that this is a brand new session. Sessions
629 loaded from saved state will get this range from the saved state.
632 set_session_range_location (0, 0);
634 /* Initial loop location, from absolute zero, length 10 seconds */
636 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
637 _locations->add (loc, true);
638 set_auto_loop_location (loc);
641 _state_of_the_state = Clean;
643 /* set up Master Out and Monitor Out if necessary */
648 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
650 // Waves Tracks: always create master bus for Tracks
651 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
652 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
660 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
661 r->input()->ensure_io (count, false, this);
662 r->output()->ensure_io (count, false, this);
668 /* prohibit auto-connect to master, because there isn't one */
669 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
673 add_routes (rl, false, false, false, PresentationInfo::max_order);
676 // Waves Tracks: Skip this. Always use autoconnection for Tracks
677 if (!ARDOUR::Profile->get_trx()) {
679 /* this allows the user to override settings with an environment variable.
682 if (no_auto_connect()) {
683 bus_profile->input_ac = AutoConnectOption (0);
684 bus_profile->output_ac = AutoConnectOption (0);
687 Config->set_input_auto_connect (bus_profile->input_ac);
688 Config->set_output_auto_connect (bus_profile->output_ac);
692 if (Config->get_use_monitor_bus() && bus_profile) {
693 add_monitor_section ();
700 Session::maybe_write_autosave()
702 if (dirty() && record_status() != Recording) {
703 save_state("", true);
708 Session::remove_pending_capture_state ()
710 std::string pending_state_file_path(_session_dir->root_path());
712 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
714 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
716 if (g_remove (pending_state_file_path.c_str()) != 0) {
717 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
718 pending_state_file_path, g_strerror (errno)) << endmsg;
722 /** Rename a state file.
723 * @param old_name Old snapshot name.
724 * @param new_name New snapshot name.
727 Session::rename_state (string old_name, string new_name)
729 if (old_name == _current_snapshot_name || old_name == _name) {
730 /* refuse to rename the current snapshot or the "main" one */
734 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
735 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
737 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
738 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
740 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
741 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
742 old_name, new_name, g_strerror(errno)) << endmsg;
746 /** Remove a state file.
747 * @param snapshot_name Snapshot name.
750 Session::remove_state (string snapshot_name)
752 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
753 // refuse to remove the current snapshot or the "main" one
757 std::string xml_path(_session_dir->root_path());
759 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
761 if (!create_backup_file (xml_path)) {
762 // don't remove it if a backup can't be made
763 // create_backup_file will log the error.
768 if (g_remove (xml_path.c_str()) != 0) {
769 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
770 xml_path, g_strerror (errno)) << endmsg;
774 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
776 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
778 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
781 std::string xml_path(_session_dir->root_path());
783 /* prevent concurrent saves from different threads */
785 Glib::Threads::Mutex::Lock lm (save_state_lock);
787 if (!_writable || (_state_of_the_state & CannotSave)) {
791 if (g_atomic_int_get(&_suspend_save)) {
795 _save_queued = false;
797 if (!_engine.connected ()) {
798 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
805 const int64_t save_start_time = g_get_monotonic_time();
808 /* tell sources we're saving first, in case they write out to a new file
809 * which should be saved with the state rather than the old one */
810 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
812 i->second->session_saved();
813 } catch (Evoral::SMF::FileError& e) {
814 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
818 SessionSaveUnderway (); /* EMIT SIGNAL */
820 bool mark_as_clean = true;
822 if (!snapshot_name.empty() && !switch_to_snapshot) {
823 mark_as_clean = false;
827 mark_as_clean = false;
828 tree.set_root (&get_template());
830 tree.set_root (&get_state());
833 if (snapshot_name.empty()) {
834 snapshot_name = _current_snapshot_name;
835 } else if (switch_to_snapshot) {
836 set_snapshot_name (snapshot_name);
839 assert (!snapshot_name.empty());
843 /* proper save: use statefile_suffix (.ardour in English) */
845 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
847 /* make a backup copy of the old file */
849 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
850 // create_backup_file will log the error
856 /* pending save: use pending_suffix (.pending in English) */
857 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
860 std::string tmp_path(_session_dir->root_path());
861 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
863 cerr << "actually writing state to " << tmp_path << endl;
865 if (!tree.write (tmp_path)) {
866 error << string_compose (_("state could not be saved to %1"), tmp_path) << 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;
875 cerr << "renaming state to " << xml_path << endl;
877 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
878 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
879 tmp_path, xml_path, g_strerror(errno)) << endmsg;
880 if (g_remove (tmp_path.c_str()) != 0) {
881 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
882 tmp_path, g_strerror (errno)) << endmsg;
890 save_history (snapshot_name);
893 bool was_dirty = dirty();
895 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
898 DirtyChanged (); /* EMIT SIGNAL */
902 StateSaved (snapshot_name); /* EMIT SIGNAL */
906 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
907 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
913 Session::restore_state (string snapshot_name)
915 if (load_state (snapshot_name) == 0) {
916 set_state (*state_tree->root(), Stateful::loading_state_version);
923 Session::load_state (string snapshot_name)
928 state_was_pending = false;
930 /* check for leftover pending state from a crashed capture attempt */
932 std::string xmlpath(_session_dir->root_path());
933 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
935 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
937 /* there is pending state from a crashed capture attempt */
939 boost::optional<int> r = AskAboutPendingState();
940 if (r.get_value_or (1)) {
941 state_was_pending = true;
945 if (!state_was_pending) {
946 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
949 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
950 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
951 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
952 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
957 state_tree = new XMLTree;
961 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
963 if (!state_tree->read (xmlpath)) {
964 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
970 XMLNode const & root (*state_tree->root());
972 if (root.name() != X_("Session")) {
973 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
979 XMLProperty const * prop;
981 if ((prop = root.property ("version")) == 0) {
982 /* no version implies very old version of Ardour */
983 Stateful::loading_state_version = 1000;
985 if (prop->value().find ('.') != string::npos) {
986 /* old school version format */
987 if (prop->value()[0] == '2') {
988 Stateful::loading_state_version = 2000;
990 Stateful::loading_state_version = 3000;
993 Stateful::loading_state_version = atoi (prop->value());
997 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
999 std::string backup_path(_session_dir->root_path());
1000 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1001 backup_path = Glib::build_filename (backup_path, backup_filename);
1003 // only create a backup for a given statefile version once
1005 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1007 VersionMismatch (xmlpath, backup_path);
1009 if (!copy_file (xmlpath, backup_path)) {;
1015 save_snapshot_name (snapshot_name);
1021 Session::load_options (const XMLNode& node)
1024 config.set_variables (node);
1029 Session::save_default_options ()
1031 return config.save_state();
1035 Session::get_state()
1041 Session::get_template()
1043 /* if we don't disable rec-enable, diskstreams
1044 will believe they need to store their capture
1045 sources in their state node.
1048 disable_record (false);
1050 return state(false);
1054 Session::state (bool full_state)
1057 XMLNode* node = new XMLNode("Session");
1061 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1062 node->add_property("version", buf);
1064 child = node->add_child ("ProgramVersion");
1065 child->add_property("created-with", created_with);
1067 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1068 child->add_property("modified-with", modified_with);
1070 /* store configuration settings */
1074 node->add_property ("name", _name);
1075 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1076 node->add_property ("sample-rate", buf);
1078 if (session_dirs.size() > 1) {
1082 vector<space_and_path>::iterator i = session_dirs.begin();
1083 vector<space_and_path>::iterator next;
1085 ++i; /* skip the first one */
1089 while (i != session_dirs.end()) {
1093 if (next != session_dirs.end()) {
1094 p += G_SEARCHPATH_SEPARATOR;
1103 child = node->add_child ("Path");
1104 child->add_content (p);
1108 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1110 /* save the ID counter */
1112 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1113 node->add_property ("id-counter", buf);
1115 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1116 node->add_property ("name-counter", buf);
1118 /* save the event ID counter */
1120 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1121 node->add_property ("event-counter", buf);
1123 /* save the VCA counter */
1125 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1126 node->add_property ("vca-counter", buf);
1128 /* various options */
1130 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1131 if (!midi_port_nodes.empty()) {
1132 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1133 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1134 midi_port_stuff->add_child_nocopy (**n);
1136 node->add_child_nocopy (*midi_port_stuff);
1139 XMLNode& cfgxml (config.get_variables ());
1141 /* exclude search-paths from template */
1142 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1143 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1144 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1146 node->add_child_nocopy (cfgxml);
1148 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1150 child = node->add_child ("Sources");
1153 Glib::Threads::Mutex::Lock sl (source_lock);
1155 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1157 /* Don't save information about non-file Sources, or
1158 * about non-destructive file sources that are empty
1159 * and unused by any regions.
1162 boost::shared_ptr<FileSource> fs;
1164 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1166 if (!fs->destructive()) {
1167 if (fs->empty() && !fs->used()) {
1172 child->add_child_nocopy (siter->second->get_state());
1177 child = node->add_child ("Regions");
1180 Glib::Threads::Mutex::Lock rl (region_lock);
1181 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1182 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1183 boost::shared_ptr<Region> r = i->second;
1184 /* only store regions not attached to playlists */
1185 if (r->playlist() == 0) {
1186 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1187 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1189 child->add_child_nocopy (r->get_state ());
1194 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1196 if (!cassocs.empty()) {
1197 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1199 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1201 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1202 i->first->id().print (buf, sizeof (buf));
1203 can->add_property (X_("copy"), buf);
1204 i->second->id().print (buf, sizeof (buf));
1205 can->add_property (X_("original"), buf);
1206 ca->add_child_nocopy (*can);
1216 node->add_child_nocopy (_locations->get_state());
1219 Locations loc (*this);
1220 // for a template, just create a new Locations, populate it
1221 // with the default start and end, and get the state for that.
1222 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1223 range->set (max_framepos, 0);
1225 XMLNode& locations_state = loc.get_state();
1227 if (ARDOUR::Profile->get_trx() && _locations) {
1228 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1229 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1230 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1231 locations_state.add_child_nocopy ((*i)->get_state ());
1235 node->add_child_nocopy (locations_state);
1238 child = node->add_child ("Bundles");
1240 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1241 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1242 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1244 child->add_child_nocopy (b->get_state());
1249 node->add_child_nocopy (_vca_manager->get_state());
1251 child = node->add_child ("Routes");
1253 boost::shared_ptr<RouteList> r = routes.reader ();
1255 RoutePublicOrderSorter cmp;
1256 RouteList public_order (*r);
1257 public_order.sort (cmp);
1259 /* the sort should have put the monitor out first */
1262 assert (_monitor_out == public_order.front());
1265 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1266 if (!(*i)->is_auditioner()) {
1268 child->add_child_nocopy ((*i)->get_state());
1270 child->add_child_nocopy ((*i)->get_template());
1276 playlists->add_state (node, full_state);
1278 child = node->add_child ("RouteGroups");
1279 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1280 child->add_child_nocopy ((*i)->get_state());
1284 XMLNode* gain_child = node->add_child ("Click");
1285 gain_child->add_child_nocopy (_click_io->state (full_state));
1286 gain_child->add_child_nocopy (_click_gain->state (full_state));
1290 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1291 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1295 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1296 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1299 node->add_child_nocopy (_speakers->get_state());
1300 node->add_child_nocopy (_tempo_map->get_state());
1301 node->add_child_nocopy (get_control_protocol_state());
1304 node->add_child_copy (*_extra_xml);
1308 Glib::Threads::Mutex::Lock lm (lua_lock);
1311 luabridge::LuaRef savedstate ((*_lua_save)());
1312 saved = savedstate.cast<std::string>();
1314 lua.collect_garbage ();
1317 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1318 std::string b64s (b64);
1321 XMLNode* script_node = new XMLNode (X_("Script"));
1322 script_node->add_property (X_("lua"), LUA_VERSION);
1323 script_node->add_content (b64s);
1324 node->add_child_nocopy (*script_node);
1331 Session::get_control_protocol_state ()
1333 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1334 return cpm.get_state();
1338 Session::set_state (const XMLNode& node, int version)
1343 XMLProperty const * prop;
1346 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1348 if (node.name() != X_("Session")) {
1349 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1353 if ((prop = node.property ("name")) != 0) {
1354 _name = prop->value ();
1357 if ((prop = node.property (X_("sample-rate"))) != 0) {
1359 _base_frame_rate = atoi (prop->value());
1360 _nominal_frame_rate = _base_frame_rate;
1362 assert (AudioEngine::instance()->running ());
1363 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1364 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1365 if (r.get_value_or (0)) {
1371 created_with = "unknown";
1372 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1373 if ((prop = child->property (X_("created-with"))) != 0) {
1374 created_with = prop->value ();
1378 setup_raid_path(_session_dir->root_path());
1380 if ((prop = node.property (X_("end-is-free"))) != 0) {
1381 _session_range_end_is_free = string_is_affirmative (prop->value());
1384 if ((prop = node.property (X_("id-counter"))) != 0) {
1386 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1387 ID::init_counter (x);
1389 /* old sessions used a timebased counter, so fake
1390 the startup ID counter based on a standard
1395 ID::init_counter (now);
1398 if ((prop = node.property (X_("name-counter"))) != 0) {
1399 init_name_id_counter (atoi (prop->value()));
1402 if ((prop = node.property (X_("event-counter"))) != 0) {
1403 Evoral::init_event_id_counter (atoi (prop->value()));
1406 if ((prop = node.property (X_("vca-counter"))) != 0) {
1408 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1409 VCA::set_next_vca_number (x);
1411 VCA::set_next_vca_number (1);
1414 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1415 _midi_ports->set_midi_port_states (child->children());
1418 IO::disable_connecting ();
1420 Stateful::save_extra_xml (node);
1422 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1423 load_options (*child);
1424 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1425 load_options (*child);
1427 error << _("Session: XML state has no options section") << endmsg;
1430 if (version >= 3000) {
1431 if ((child = find_named_node (node, "Metadata")) == 0) {
1432 warning << _("Session: XML state has no metadata section") << endmsg;
1433 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1438 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1439 _speakers->set_state (*child, version);
1442 if ((child = find_named_node (node, "Sources")) == 0) {
1443 error << _("Session: XML state has no sources section") << endmsg;
1445 } else if (load_sources (*child)) {
1449 if ((child = find_named_node (node, "TempoMap")) == 0) {
1450 error << _("Session: XML state has no Tempo Map section") << endmsg;
1452 } else if (_tempo_map->set_state (*child, version)) {
1456 if ((child = find_named_node (node, "Locations")) == 0) {
1457 error << _("Session: XML state has no locations section") << endmsg;
1459 } else if (_locations->set_state (*child, version)) {
1463 locations_changed ();
1465 if (_session_range_location) {
1466 AudioFileSource::set_header_position_offset (_session_range_location->start());
1469 if ((child = find_named_node (node, "Regions")) == 0) {
1470 error << _("Session: XML state has no Regions section") << endmsg;
1472 } else if (load_regions (*child)) {
1476 if ((child = find_named_node (node, "Playlists")) == 0) {
1477 error << _("Session: XML state has no playlists section") << endmsg;
1479 } else if (playlists->load (*this, *child)) {
1483 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1485 } else if (playlists->load_unused (*this, *child)) {
1489 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1490 if (load_compounds (*child)) {
1495 if (version >= 3000) {
1496 if ((child = find_named_node (node, "Bundles")) == 0) {
1497 warning << _("Session: XML state has no bundles section") << endmsg;
1500 /* We can't load Bundles yet as they need to be able
1501 to convert from port names to Port objects, which can't happen until
1503 _bundle_xml_node = new XMLNode (*child);
1507 if (version < 3000) {
1508 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1509 error << _("Session: XML state has no diskstreams section") << endmsg;
1511 } else if (load_diskstreams_2X (*child, version)) {
1516 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1517 _vca_manager->set_state (*child, version);
1520 if ((child = find_named_node (node, "Routes")) == 0) {
1521 error << _("Session: XML state has no routes section") << endmsg;
1523 } else if (load_routes (*child, version)) {
1527 /* Now that we have Routes and masters loaded, connect them if appropriate */
1529 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1531 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1532 _diskstreams_2X.clear ();
1534 if (version >= 3000) {
1536 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1537 error << _("Session: XML state has no route groups section") << endmsg;
1539 } else if (load_route_groups (*child, version)) {
1543 } else if (version < 3000) {
1545 if ((child = find_named_node (node, "EditGroups")) == 0) {
1546 error << _("Session: XML state has no edit groups section") << endmsg;
1548 } else if (load_route_groups (*child, version)) {
1552 if ((child = find_named_node (node, "MixGroups")) == 0) {
1553 error << _("Session: XML state has no mix groups section") << endmsg;
1555 } else if (load_route_groups (*child, version)) {
1560 if ((child = find_named_node (node, "Click")) == 0) {
1561 warning << _("Session: XML state has no click section") << endmsg;
1562 } else if (_click_io) {
1563 setup_click_state (&node);
1566 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1567 ControlProtocolManager::instance().set_state (*child, version);
1570 if ((child = find_named_node (node, "Script"))) {
1571 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1572 if (!(*n)->is_content ()) { continue; }
1574 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1576 Glib::Threads::Mutex::Lock lm (lua_lock);
1577 (*_lua_load)(std::string ((const char*)buf, size));
1578 } catch (luabridge::LuaException const& e) {
1579 cerr << "LuaException:" << e.what () << endl;
1585 update_route_record_state ();
1587 /* here beginneth the second phase ... */
1588 set_snapshot_name (_current_snapshot_name);
1590 StateReady (); /* EMIT SIGNAL */
1603 Session::load_routes (const XMLNode& node, int version)
1606 XMLNodeConstIterator niter;
1607 RouteList new_routes;
1609 nlist = node.children();
1613 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1615 boost::shared_ptr<Route> route;
1616 if (version < 3000) {
1617 route = XMLRouteFactory_2X (**niter, version);
1619 route = XMLRouteFactory (**niter, version);
1623 error << _("Session: cannot create Route from XML description.") << endmsg;
1627 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1629 new_routes.push_back (route);
1632 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1634 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1636 BootMessage (_("Finished adding tracks/busses"));
1641 boost::shared_ptr<Route>
1642 Session::XMLRouteFactory (const XMLNode& node, int version)
1644 boost::shared_ptr<Route> ret;
1646 if (node.name() != "Route") {
1650 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1652 DataType type = DataType::AUDIO;
1653 XMLProperty const * prop = node.property("default-type");
1656 type = DataType (prop->value());
1659 assert (type != DataType::NIL);
1663 boost::shared_ptr<Track> track;
1665 if (type == DataType::AUDIO) {
1666 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1668 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1671 if (track->init()) {
1675 if (track->set_state (node, version)) {
1679 BOOST_MARK_TRACK (track);
1683 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1684 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1686 if (r->init () == 0 && r->set_state (node, version) == 0) {
1687 BOOST_MARK_ROUTE (r);
1695 boost::shared_ptr<Route>
1696 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1698 boost::shared_ptr<Route> ret;
1700 if (node.name() != "Route") {
1704 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1706 ds_prop = node.property (X_("diskstream"));
1709 DataType type = DataType::AUDIO;
1710 XMLProperty const * prop = node.property("default-type");
1713 type = DataType (prop->value());
1716 assert (type != DataType::NIL);
1720 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1721 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1725 if (i == _diskstreams_2X.end()) {
1726 error << _("Could not find diskstream for route") << endmsg;
1727 return boost::shared_ptr<Route> ();
1730 boost::shared_ptr<Track> track;
1732 if (type == DataType::AUDIO) {
1733 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1735 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1738 if (track->init()) {
1742 if (track->set_state (node, version)) {
1746 track->set_diskstream (*i);
1748 BOOST_MARK_TRACK (track);
1752 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1753 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1755 if (r->init () == 0 && r->set_state (node, version) == 0) {
1756 BOOST_MARK_ROUTE (r);
1765 Session::load_regions (const XMLNode& node)
1768 XMLNodeConstIterator niter;
1769 boost::shared_ptr<Region> region;
1771 nlist = node.children();
1775 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1776 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1777 error << _("Session: cannot create Region from XML description.");
1778 XMLProperty const * name = (**niter).property("name");
1781 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1792 Session::load_compounds (const XMLNode& node)
1794 XMLNodeList calist = node.children();
1795 XMLNodeConstIterator caiter;
1796 XMLProperty const * caprop;
1798 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1799 XMLNode* ca = *caiter;
1803 if ((caprop = ca->property (X_("original"))) == 0) {
1806 orig_id = caprop->value();
1808 if ((caprop = ca->property (X_("copy"))) == 0) {
1811 copy_id = caprop->value();
1813 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1814 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1816 if (!orig || !copy) {
1817 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1823 RegionFactory::add_compound_association (orig, copy);
1830 Session::load_nested_sources (const XMLNode& node)
1833 XMLNodeConstIterator niter;
1835 nlist = node.children();
1837 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1838 if ((*niter)->name() == "Source") {
1840 /* it may already exist, so don't recreate it unnecessarily
1843 XMLProperty const * prop = (*niter)->property (X_("id"));
1845 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1849 ID source_id (prop->value());
1851 if (!source_by_id (source_id)) {
1854 SourceFactory::create (*this, **niter, true);
1856 catch (failed_constructor& err) {
1857 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1864 boost::shared_ptr<Region>
1865 Session::XMLRegionFactory (const XMLNode& node, bool full)
1867 XMLProperty const * type = node.property("type");
1871 const XMLNodeList& nlist = node.children();
1873 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1874 XMLNode *child = (*niter);
1875 if (child->name() == "NestedSource") {
1876 load_nested_sources (*child);
1880 if (!type || type->value() == "audio") {
1881 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1882 } else if (type->value() == "midi") {
1883 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1886 } catch (failed_constructor& err) {
1887 return boost::shared_ptr<Region> ();
1890 return boost::shared_ptr<Region> ();
1893 boost::shared_ptr<AudioRegion>
1894 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1896 XMLProperty const * prop;
1897 boost::shared_ptr<Source> source;
1898 boost::shared_ptr<AudioSource> as;
1900 SourceList master_sources;
1901 uint32_t nchans = 1;
1904 if (node.name() != X_("Region")) {
1905 return boost::shared_ptr<AudioRegion>();
1908 if ((prop = node.property (X_("channels"))) != 0) {
1909 nchans = atoi (prop->value().c_str());
1912 if ((prop = node.property ("name")) == 0) {
1913 cerr << "no name for this region\n";
1917 if ((prop = node.property (X_("source-0"))) == 0) {
1918 if ((prop = node.property ("source")) == 0) {
1919 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1920 return boost::shared_ptr<AudioRegion>();
1924 PBD::ID s_id (prop->value());
1926 if ((source = source_by_id (s_id)) == 0) {
1927 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1928 return boost::shared_ptr<AudioRegion>();
1931 as = boost::dynamic_pointer_cast<AudioSource>(source);
1933 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1934 return boost::shared_ptr<AudioRegion>();
1937 sources.push_back (as);
1939 /* pickup other channels */
1941 for (uint32_t n=1; n < nchans; ++n) {
1942 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1943 if ((prop = node.property (buf)) != 0) {
1945 PBD::ID id2 (prop->value());
1947 if ((source = source_by_id (id2)) == 0) {
1948 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1949 return boost::shared_ptr<AudioRegion>();
1952 as = boost::dynamic_pointer_cast<AudioSource>(source);
1954 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1955 return boost::shared_ptr<AudioRegion>();
1957 sources.push_back (as);
1961 for (uint32_t n = 0; n < nchans; ++n) {
1962 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1963 if ((prop = node.property (buf)) != 0) {
1965 PBD::ID id2 (prop->value());
1967 if ((source = source_by_id (id2)) == 0) {
1968 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1969 return boost::shared_ptr<AudioRegion>();
1972 as = boost::dynamic_pointer_cast<AudioSource>(source);
1974 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1975 return boost::shared_ptr<AudioRegion>();
1977 master_sources.push_back (as);
1982 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1984 /* a final detail: this is the one and only place that we know how long missing files are */
1986 if (region->whole_file()) {
1987 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1988 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1990 sfp->set_length (region->length());
1995 if (!master_sources.empty()) {
1996 if (master_sources.size() != nchans) {
1997 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1999 region->set_master_sources (master_sources);
2007 catch (failed_constructor& err) {
2008 return boost::shared_ptr<AudioRegion>();
2012 boost::shared_ptr<MidiRegion>
2013 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2015 XMLProperty const * prop;
2016 boost::shared_ptr<Source> source;
2017 boost::shared_ptr<MidiSource> ms;
2020 if (node.name() != X_("Region")) {
2021 return boost::shared_ptr<MidiRegion>();
2024 if ((prop = node.property ("name")) == 0) {
2025 cerr << "no name for this region\n";
2029 if ((prop = node.property (X_("source-0"))) == 0) {
2030 if ((prop = node.property ("source")) == 0) {
2031 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2032 return boost::shared_ptr<MidiRegion>();
2036 PBD::ID s_id (prop->value());
2038 if ((source = source_by_id (s_id)) == 0) {
2039 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2040 return boost::shared_ptr<MidiRegion>();
2043 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2045 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2046 return boost::shared_ptr<MidiRegion>();
2049 sources.push_back (ms);
2052 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2053 /* a final detail: this is the one and only place that we know how long missing files are */
2055 if (region->whole_file()) {
2056 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2057 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2059 sfp->set_length (region->length());
2067 catch (failed_constructor& err) {
2068 return boost::shared_ptr<MidiRegion>();
2073 Session::get_sources_as_xml ()
2076 XMLNode* node = new XMLNode (X_("Sources"));
2077 Glib::Threads::Mutex::Lock lm (source_lock);
2079 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2080 node->add_child_nocopy (i->second->get_state());
2087 Session::reset_write_sources (bool mark_write_complete, bool force)
2089 boost::shared_ptr<RouteList> rl = routes.reader();
2090 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2091 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2093 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2094 tr->reset_write_sources(mark_write_complete, force);
2095 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2101 Session::load_sources (const XMLNode& node)
2104 XMLNodeConstIterator niter;
2105 boost::shared_ptr<Source> source; /* don't need this but it stops some
2106 * versions of gcc complaining about
2107 * discarded return values.
2110 nlist = node.children();
2114 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2115 #ifdef PLATFORM_WINDOWS
2121 #ifdef PLATFORM_WINDOWS
2122 // do not show "insert media" popups (files embedded from removable media).
2123 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2125 if ((source = XMLSourceFactory (**niter)) == 0) {
2126 error << _("Session: cannot create Source from XML description.") << endmsg;
2128 #ifdef PLATFORM_WINDOWS
2129 SetErrorMode(old_mode);
2132 } catch (MissingSource& err) {
2133 #ifdef PLATFORM_WINDOWS
2134 SetErrorMode(old_mode);
2139 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2140 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2141 PROGRAM_NAME) << endmsg;
2145 if (!no_questions_about_missing_files) {
2146 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2151 switch (user_choice) {
2153 /* user added a new search location, so try again */
2158 /* user asked to quit the entire session load
2163 no_questions_about_missing_files = true;
2167 no_questions_about_missing_files = true;
2174 case DataType::AUDIO:
2175 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2178 case DataType::MIDI:
2179 /* The MIDI file is actually missing so
2180 * just create a new one in the same
2181 * location. Do not announce its
2185 if (!Glib::path_is_absolute (err.path)) {
2186 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2188 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2193 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2194 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2195 /* reset ID to match the missing one */
2196 source->set_id (**niter);
2197 /* Now we can announce it */
2198 SourceFactory::SourceCreated (source);
2209 boost::shared_ptr<Source>
2210 Session::XMLSourceFactory (const XMLNode& node)
2212 if (node.name() != "Source") {
2213 return boost::shared_ptr<Source>();
2217 /* note: do peak building in another thread when loading session state */
2218 return SourceFactory::create (*this, node, true);
2221 catch (failed_constructor& err) {
2222 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2223 return boost::shared_ptr<Source>();
2228 Session::save_template (string template_name, bool replace_existing)
2230 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2234 bool absolute_path = Glib::path_is_absolute (template_name);
2236 /* directory to put the template in */
2237 std::string template_dir_path;
2239 if (!absolute_path) {
2240 std::string user_template_dir(user_template_directory());
2242 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2243 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2244 user_template_dir, g_strerror (errno)) << endmsg;
2248 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2250 template_dir_path = template_name;
2253 if (!ARDOUR::Profile->get_trx()) {
2254 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2255 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2256 template_dir_path) << endmsg;
2260 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2261 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2262 template_dir_path, g_strerror (errno)) << endmsg;
2268 std::string template_file_path;
2270 if (ARDOUR::Profile->get_trx()) {
2271 template_file_path = template_name;
2273 if (absolute_path) {
2274 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2276 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2280 SessionSaveUnderway (); /* EMIT SIGNAL */
2285 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2286 tree.set_root (&get_template());
2289 if (!tree.write (template_file_path)) {
2290 error << _("template not saved") << endmsg;
2294 store_recent_templates (template_file_path);
2300 Session::refresh_disk_space ()
2302 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2304 Glib::Threads::Mutex::Lock lm (space_lock);
2306 /* get freespace on every FS that is part of the session path */
2308 _total_free_4k_blocks = 0;
2309 _total_free_4k_blocks_uncertain = false;
2311 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2312 #if defined(__NetBSD__)
2313 struct statvfs statfsbuf;
2315 statvfs (i->path.c_str(), &statfsbuf);
2317 struct statfs statfsbuf;
2319 statfs (i->path.c_str(), &statfsbuf);
2321 double const scale = statfsbuf.f_bsize / 4096.0;
2323 /* See if this filesystem is read-only */
2324 struct statvfs statvfsbuf;
2325 statvfs (i->path.c_str(), &statvfsbuf);
2327 /* f_bavail can be 0 if it is undefined for whatever
2328 filesystem we are looking at; Samba shares mounted
2329 via GVFS are an example of this.
2331 if (statfsbuf.f_bavail == 0) {
2332 /* block count unknown */
2334 i->blocks_unknown = true;
2335 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2336 /* read-only filesystem */
2338 i->blocks_unknown = false;
2340 /* read/write filesystem with known space */
2341 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2342 i->blocks_unknown = false;
2345 _total_free_4k_blocks += i->blocks;
2346 if (i->blocks_unknown) {
2347 _total_free_4k_blocks_uncertain = true;
2350 #elif defined PLATFORM_WINDOWS
2351 vector<string> scanned_volumes;
2352 vector<string>::iterator j;
2353 vector<space_and_path>::iterator i;
2354 DWORD nSectorsPerCluster, nBytesPerSector,
2355 nFreeClusters, nTotalClusters;
2359 _total_free_4k_blocks = 0;
2361 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2362 strncpy (disk_drive, (*i).path.c_str(), 3);
2366 volume_found = false;
2367 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2369 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2370 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2371 i->blocks = (uint32_t)(nFreeBytes / 4096);
2373 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2374 if (0 == j->compare(disk_drive)) {
2375 volume_found = true;
2380 if (!volume_found) {
2381 scanned_volumes.push_back(disk_drive);
2382 _total_free_4k_blocks += i->blocks;
2387 if (0 == _total_free_4k_blocks) {
2388 strncpy (disk_drive, path().c_str(), 3);
2391 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2393 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2394 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2395 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2402 Session::get_best_session_directory_for_new_audio ()
2404 vector<space_and_path>::iterator i;
2405 string result = _session_dir->root_path();
2407 /* handle common case without system calls */
2409 if (session_dirs.size() == 1) {
2413 /* OK, here's the algorithm we're following here:
2415 We want to select which directory to use for
2416 the next file source to be created. Ideally,
2417 we'd like to use a round-robin process so as to
2418 get maximum performance benefits from splitting
2419 the files across multiple disks.
2421 However, in situations without much diskspace, an
2422 RR approach may end up filling up a filesystem
2423 with new files while others still have space.
2424 Its therefore important to pay some attention to
2425 the freespace in the filesystem holding each
2426 directory as well. However, if we did that by
2427 itself, we'd keep creating new files in the file
2428 system with the most space until it was as full
2429 as all others, thus negating any performance
2430 benefits of this RAID-1 like approach.
2432 So, we use a user-configurable space threshold. If
2433 there are at least 2 filesystems with more than this
2434 much space available, we use RR selection between them.
2435 If not, then we pick the filesystem with the most space.
2437 This gets a good balance between the two
2441 refresh_disk_space ();
2443 int free_enough = 0;
2445 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2446 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2451 if (free_enough >= 2) {
2452 /* use RR selection process, ensuring that the one
2456 i = last_rr_session_dir;
2459 if (++i == session_dirs.end()) {
2460 i = session_dirs.begin();
2463 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2464 SessionDirectory sdir(i->path);
2465 if (sdir.create ()) {
2467 last_rr_session_dir = i;
2472 } while (i != last_rr_session_dir);
2476 /* pick FS with the most freespace (and that
2477 seems to actually work ...)
2480 vector<space_and_path> sorted;
2481 space_and_path_ascending_cmp cmp;
2483 sorted = session_dirs;
2484 sort (sorted.begin(), sorted.end(), cmp);
2486 for (i = sorted.begin(); i != sorted.end(); ++i) {
2487 SessionDirectory sdir(i->path);
2488 if (sdir.create ()) {
2490 last_rr_session_dir = i;
2500 Session::automation_dir () const
2502 return Glib::build_filename (_path, automation_dir_name);
2506 Session::analysis_dir () const
2508 return Glib::build_filename (_path, analysis_dir_name);
2512 Session::plugins_dir () const
2514 return Glib::build_filename (_path, plugins_dir_name);
2518 Session::externals_dir () const
2520 return Glib::build_filename (_path, externals_dir_name);
2524 Session::load_bundles (XMLNode const & node)
2526 XMLNodeList nlist = node.children();
2527 XMLNodeConstIterator niter;
2531 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2532 if ((*niter)->name() == "InputBundle") {
2533 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2534 } else if ((*niter)->name() == "OutputBundle") {
2535 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2537 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2546 Session::load_route_groups (const XMLNode& node, int version)
2548 XMLNodeList nlist = node.children();
2549 XMLNodeConstIterator niter;
2553 if (version >= 3000) {
2555 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2556 if ((*niter)->name() == "RouteGroup") {
2557 RouteGroup* rg = new RouteGroup (*this, "");
2558 add_route_group (rg);
2559 rg->set_state (**niter, version);
2563 } else if (version < 3000) {
2565 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2566 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2567 RouteGroup* rg = new RouteGroup (*this, "");
2568 add_route_group (rg);
2569 rg->set_state (**niter, version);
2578 state_file_filter (const string &str, void* /*arg*/)
2580 return (str.length() > strlen(statefile_suffix) &&
2581 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2585 remove_end(string state)
2587 string statename(state);
2589 string::size_type start,end;
2590 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2591 statename = statename.substr (start+1);
2594 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2595 end = statename.length();
2598 return string(statename.substr (0, end));
2602 Session::possible_states (string path)
2604 vector<string> states;
2605 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2607 transform(states.begin(), states.end(), states.begin(), remove_end);
2609 sort (states.begin(), states.end());
2615 Session::possible_states () const
2617 return possible_states(_path);
2621 Session::add_route_group (RouteGroup* g)
2623 _route_groups.push_back (g);
2624 route_group_added (g); /* EMIT SIGNAL */
2626 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2627 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2628 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2634 Session::remove_route_group (RouteGroup& rg)
2636 list<RouteGroup*>::iterator i;
2638 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2639 _route_groups.erase (i);
2642 route_group_removed (); /* EMIT SIGNAL */
2646 /** Set a new order for our route groups, without adding or removing any.
2647 * @param groups Route group list in the new order.
2650 Session::reorder_route_groups (list<RouteGroup*> groups)
2652 _route_groups = groups;
2654 route_groups_reordered (); /* EMIT SIGNAL */
2660 Session::route_group_by_name (string name)
2662 list<RouteGroup *>::iterator i;
2664 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2665 if ((*i)->name() == name) {
2673 Session::all_route_group() const
2675 return *_all_route_group;
2679 Session::add_commands (vector<Command*> const & cmds)
2681 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2687 Session::add_command (Command* const cmd)
2689 assert (_current_trans);
2690 DEBUG_UNDO_HISTORY (
2691 string_compose ("Current Undo Transaction %1, adding command: %2",
2692 _current_trans->name (),
2694 _current_trans->add_command (cmd);
2697 PBD::StatefulDiffCommand*
2698 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2700 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2706 Session::begin_reversible_command (const string& name)
2708 begin_reversible_command (g_quark_from_string (name.c_str ()));
2711 /** Begin a reversible command using a GQuark to identify it.
2712 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2713 * but there must be as many begin...()s as there are commit...()s.
2716 Session::begin_reversible_command (GQuark q)
2718 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2719 to hold all the commands that are committed. This keeps the order of
2720 commands correct in the history.
2723 if (_current_trans == 0) {
2724 DEBUG_UNDO_HISTORY (string_compose (
2725 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2727 /* start a new transaction */
2728 assert (_current_trans_quarks.empty ());
2729 _current_trans = new UndoTransaction();
2730 _current_trans->set_name (g_quark_to_string (q));
2732 DEBUG_UNDO_HISTORY (
2733 string_compose ("Begin Reversible Command, current transaction: %1",
2734 _current_trans->name ()));
2737 _current_trans_quarks.push_front (q);
2741 Session::abort_reversible_command ()
2743 if (_current_trans != 0) {
2744 DEBUG_UNDO_HISTORY (
2745 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2746 _current_trans->clear();
2747 delete _current_trans;
2749 _current_trans_quarks.clear();
2754 Session::commit_reversible_command (Command *cmd)
2756 assert (_current_trans);
2757 assert (!_current_trans_quarks.empty ());
2762 DEBUG_UNDO_HISTORY (
2763 string_compose ("Current Undo Transaction %1, adding command: %2",
2764 _current_trans->name (),
2766 _current_trans->add_command (cmd);
2769 DEBUG_UNDO_HISTORY (
2770 string_compose ("Commit Reversible Command, current transaction: %1",
2771 _current_trans->name ()));
2773 _current_trans_quarks.pop_front ();
2775 if (!_current_trans_quarks.empty ()) {
2776 DEBUG_UNDO_HISTORY (
2777 string_compose ("Commit Reversible Command, transaction is not "
2778 "top-level, current transaction: %1",
2779 _current_trans->name ()));
2780 /* the transaction we're committing is not the top-level one */
2784 if (_current_trans->empty()) {
2785 /* no commands were added to the transaction, so just get rid of it */
2786 DEBUG_UNDO_HISTORY (
2787 string_compose ("Commit Reversible Command, No commands were "
2788 "added to current transaction: %1",
2789 _current_trans->name ()));
2790 delete _current_trans;
2795 gettimeofday (&now, 0);
2796 _current_trans->set_timestamp (now);
2798 _history.add (_current_trans);
2803 accept_all_audio_files (const string& path, void* /*arg*/)
2805 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2809 if (!AudioFileSource::safe_audio_file_extension (path)) {
2817 accept_all_midi_files (const string& path, void* /*arg*/)
2819 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2823 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2824 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2825 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2829 accept_all_state_files (const string& path, void* /*arg*/)
2831 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2835 std::string const statefile_ext (statefile_suffix);
2836 if (path.length() >= statefile_ext.length()) {
2837 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2844 Session::find_all_sources (string path, set<string>& result)
2849 if (!tree.read (path)) {
2853 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2858 XMLNodeConstIterator niter;
2860 nlist = node->children();
2864 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2866 XMLProperty const * prop;
2868 if ((prop = (*niter)->property (X_("type"))) == 0) {
2872 DataType type (prop->value());
2874 if ((prop = (*niter)->property (X_("name"))) == 0) {
2878 if (Glib::path_is_absolute (prop->value())) {
2879 /* external file, ignore */
2887 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2888 result.insert (found_path);
2896 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2898 vector<string> state_files;
2900 string this_snapshot_path;
2906 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2907 ripped = ripped.substr (0, ripped.length() - 1);
2910 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2912 if (state_files.empty()) {
2917 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2918 this_snapshot_path += statefile_suffix;
2920 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2922 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2924 if (exclude_this_snapshot && *i == this_snapshot_path) {
2925 cerr << "\texcluded\n";
2930 if (find_all_sources (*i, result) < 0) {
2938 struct RegionCounter {
2939 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2940 AudioSourceList::iterator iter;
2941 boost::shared_ptr<Region> region;
2944 RegionCounter() : count (0) {}
2948 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2950 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2951 return r.get_value_or (1);
2955 Session::cleanup_regions ()
2957 bool removed = false;
2958 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2960 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2962 uint32_t used = playlists->region_use_count (i->second);
2964 if (used == 0 && !i->second->automatic ()) {
2965 boost::weak_ptr<Region> w = i->second;
2968 RegionFactory::map_remove (w);
2975 // re-check to remove parent references of compound regions
2976 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2977 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2981 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2982 if (0 == playlists->region_use_count (i->second)) {
2983 boost::weak_ptr<Region> w = i->second;
2985 RegionFactory::map_remove (w);
2992 /* dump the history list */
2999 Session::can_cleanup_peakfiles () const
3001 if (deletion_in_progress()) {
3004 if (!_writable || (_state_of_the_state & CannotSave)) {
3005 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3008 if (record_status() == Recording) {
3009 error << _("Cannot cleanup peak-files while recording") << endmsg;
3016 Session::cleanup_peakfiles ()
3018 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3023 assert (can_cleanup_peakfiles ());
3024 assert (!peaks_cleanup_in_progres());
3026 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3028 int timeout = 5000; // 5 seconds
3029 while (!SourceFactory::files_with_peaks.empty()) {
3030 Glib::usleep (1000);
3031 if (--timeout < 0) {
3032 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3033 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3038 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3039 boost::shared_ptr<AudioSource> as;
3040 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3041 as->close_peakfile();
3045 PBD::clear_directory (session_directory().peak_path());
3047 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3049 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3050 boost::shared_ptr<AudioSource> as;
3051 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3052 SourceFactory::setup_peakfile(as, true);
3059 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3061 pl->deep_sources (*all_sources);
3065 Session::cleanup_sources (CleanupReport& rep)
3067 // FIXME: needs adaptation to midi
3069 vector<boost::shared_ptr<Source> > dead_sources;
3072 vector<string> candidates;
3073 vector<string> unused;
3074 set<string> sources_used_by_all_snapshots;
3081 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3083 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3085 /* this is mostly for windows which doesn't allow file
3086 * renaming if the file is in use. But we don't special
3087 * case it because we need to know if this causes
3088 * problems, and the easiest way to notice that is to
3089 * keep it in place for all platforms.
3092 request_stop (false);
3094 _butler->wait_until_finished ();
3096 /* consider deleting all unused playlists */
3098 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3103 /* sync the "all regions" property of each playlist with its current state
3106 playlists->sync_all_regions_with_regions ();
3108 /* find all un-used sources */
3113 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3115 SourceMap::iterator tmp;
3120 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3124 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3125 dead_sources.push_back (i->second);
3126 i->second->drop_references ();
3132 /* build a list of all the possible audio directories for the session */
3134 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3135 SessionDirectory sdir ((*i).path);
3136 asp += sdir.sound_path();
3138 audio_path += asp.to_string();
3141 /* build a list of all the possible midi directories for the session */
3143 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3144 SessionDirectory sdir ((*i).path);
3145 msp += sdir.midi_path();
3147 midi_path += msp.to_string();
3149 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3150 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3152 /* add sources from all other snapshots as "used", but don't use this
3153 snapshot because the state file on disk still references sources we
3154 may have already dropped.
3157 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3159 /* Although the region factory has a list of all regions ever created
3160 * for this session, we're only interested in regions actually in
3161 * playlists right now. So merge all playlist regions lists together.
3163 * This will include the playlists used within compound regions.
3166 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3168 /* add our current source list
3171 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3172 boost::shared_ptr<FileSource> fs;
3173 SourceMap::iterator tmp = i;
3176 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3182 /* this is mostly for windows which doesn't allow file
3183 * renaming if the file is in use. But we do not special
3184 * case it because we need to know if this causes
3185 * problems, and the easiest way to notice that is to
3186 * keep it in place for all platforms.
3191 if (!fs->is_stub()) {
3193 /* Note that we're checking a list of all
3194 * sources across all snapshots with the list
3195 * of sources used by this snapshot.
3198 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3199 /* this source is in use by this snapshot */
3200 sources_used_by_all_snapshots.insert (fs->path());
3201 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3203 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3204 /* this source is NOT in use by this snapshot
3207 /* remove all related regions from RegionFactory master list
3210 RegionFactory::remove_regions_using_source (i->second);
3212 /* remove from our current source list
3213 * also. We may not remove it from
3214 * disk, because it may be used by
3215 * other snapshots, but it isn't used inside this
3216 * snapshot anymore, so we don't need a
3227 /* now check each candidate source to see if it exists in the list of
3228 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3231 cerr << "Candidates: " << candidates.size() << endl;
3232 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3234 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3239 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3241 tmppath1 = canonical_path (spath);
3242 tmppath2 = canonical_path ((*i));
3244 cerr << "\t => " << tmppath2 << endl;
3246 if (tmppath1 == tmppath2) {
3253 unused.push_back (spath);
3257 cerr << "Actually unused: " << unused.size() << endl;
3259 if (unused.empty()) {
3265 /* now try to move all unused files into the "dead" directory(ies) */
3267 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3272 /* don't move the file across filesystems, just
3273 stick it in the `dead_dir_name' directory
3274 on whichever filesystem it was already on.
3277 if ((*x).find ("/sounds/") != string::npos) {
3279 /* old school, go up 1 level */
3281 newpath = Glib::path_get_dirname (*x); // "sounds"
3282 newpath = Glib::path_get_dirname (newpath); // "session-name"
3286 /* new school, go up 4 levels */
3288 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3289 newpath = Glib::path_get_dirname (newpath); // "session-name"
3290 newpath = Glib::path_get_dirname (newpath); // "interchange"
3291 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3294 newpath = Glib::build_filename (newpath, dead_dir_name);
3296 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3297 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3301 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3303 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3305 /* the new path already exists, try versioning */
3307 char buf[PATH_MAX+1];
3311 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3314 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3315 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3319 if (version == 999) {
3320 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3324 newpath = newpath_v;
3329 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3330 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3331 newpath, g_strerror (errno)) << endmsg;
3335 /* see if there an easy to find peakfile for this file, and remove it.
3338 string base = Glib::path_get_basename (*x);
3339 base += "%A"; /* this is what we add for the channel suffix of all native files,
3340 or for the first channel of embedded files. it will miss
3341 some peakfiles for other channels
3343 string peakpath = construct_peak_filepath (base);
3345 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3346 if (::g_unlink (peakpath.c_str ()) != 0) {
3347 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3348 g_strerror (errno)) << endmsg;
3349 /* try to back out */
3350 ::g_rename (newpath.c_str (), _path.c_str ());
3355 rep.paths.push_back (*x);
3356 rep.space += statbuf.st_size;
3359 /* dump the history list */
3363 /* save state so we don't end up a session file
3364 referring to non-existent sources.
3371 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3377 Session::cleanup_trash_sources (CleanupReport& rep)
3379 // FIXME: needs adaptation for MIDI
3381 vector<space_and_path>::iterator i;
3387 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3389 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3391 clear_directory (dead_dir, &rep.space, &rep.paths);
3398 Session::set_dirty ()
3400 /* never mark session dirty during loading */
3402 if (_state_of_the_state & Loading) {
3406 bool was_dirty = dirty();
3408 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3412 DirtyChanged(); /* EMIT SIGNAL */
3418 Session::set_clean ()
3420 bool was_dirty = dirty();
3422 _state_of_the_state = Clean;
3426 DirtyChanged(); /* EMIT SIGNAL */
3431 Session::set_deletion_in_progress ()
3433 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3437 Session::clear_deletion_in_progress ()
3439 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3443 Session::add_controllable (boost::shared_ptr<Controllable> c)
3445 /* this adds a controllable to the list managed by the Session.
3446 this is a subset of those managed by the Controllable class
3447 itself, and represents the only ones whose state will be saved
3448 as part of the session.
3451 Glib::Threads::Mutex::Lock lm (controllables_lock);
3452 controllables.insert (c);
3455 struct null_deleter { void operator()(void const *) const {} };
3458 Session::remove_controllable (Controllable* c)
3460 if (_state_of_the_state & Deletion) {
3464 Glib::Threads::Mutex::Lock lm (controllables_lock);
3466 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3468 if (x != controllables.end()) {
3469 controllables.erase (x);
3473 boost::shared_ptr<Controllable>
3474 Session::controllable_by_id (const PBD::ID& id)
3476 Glib::Threads::Mutex::Lock lm (controllables_lock);
3478 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3479 if ((*i)->id() == id) {
3484 return boost::shared_ptr<Controllable>();
3487 boost::shared_ptr<Controllable>
3488 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3490 boost::shared_ptr<Controllable> c;
3491 boost::shared_ptr<Stripable> s;
3492 boost::shared_ptr<Route> r;
3494 switch (desc.top_level_type()) {
3495 case ControllableDescriptor::NamedRoute:
3497 std::string str = desc.top_level_name();
3499 if (str == "Master" || str == "master") {
3501 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3503 } else if (str == "auditioner") {
3506 s = route_by_name (desc.top_level_name());
3512 case ControllableDescriptor::PresentationOrderRoute:
3513 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3516 case ControllableDescriptor::PresentationOrderTrack:
3517 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3520 case ControllableDescriptor::PresentationOrderBus:
3521 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3524 case ControllableDescriptor::PresentationOrderVCA:
3525 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3528 case ControllableDescriptor::SelectionCount:
3529 s = route_by_selected_count (desc.selection_id());
3537 r = boost::dynamic_pointer_cast<Route> (s);
3539 switch (desc.subtype()) {
3540 case ControllableDescriptor::Gain:
3541 c = s->gain_control ();
3544 case ControllableDescriptor::Trim:
3545 c = s->trim_control ();
3548 case ControllableDescriptor::Solo:
3549 c = s->solo_control();
3552 case ControllableDescriptor::Mute:
3553 c = s->mute_control();
3556 case ControllableDescriptor::Recenable:
3557 c = s->rec_enable_control ();
3560 case ControllableDescriptor::PanDirection:
3561 c = s->pan_azimuth_control();
3564 case ControllableDescriptor::PanWidth:
3565 c = s->pan_width_control();
3568 case ControllableDescriptor::PanElevation:
3569 c = s->pan_elevation_control();
3572 case ControllableDescriptor::Balance:
3573 /* XXX simple pan control */
3576 case ControllableDescriptor::PluginParameter:
3578 uint32_t plugin = desc.target (0);
3579 uint32_t parameter_index = desc.target (1);
3581 /* revert to zero based counting */
3587 if (parameter_index > 0) {
3595 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3598 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3599 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3604 case ControllableDescriptor::SendGain: {
3605 uint32_t send = desc.target (0);
3612 c = r->send_level_controllable (send);
3617 /* relax and return a null pointer */
3625 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3628 Stateful::add_instant_xml (node, _path);
3631 if (write_to_config) {
3632 Config->add_instant_xml (node);
3637 Session::instant_xml (const string& node_name)
3639 return Stateful::instant_xml (node_name, _path);
3643 Session::save_history (string snapshot_name)
3651 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3652 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3656 if (snapshot_name.empty()) {
3657 snapshot_name = _current_snapshot_name;
3660 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3661 const string backup_filename = history_filename + backup_suffix;
3662 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3663 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3665 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3666 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3667 error << _("could not backup old history file, current history not saved") << endmsg;
3672 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3674 if (!tree.write (xml_path))
3676 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3678 if (g_remove (xml_path.c_str()) != 0) {
3679 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3680 xml_path, g_strerror (errno)) << endmsg;
3682 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3683 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3684 backup_path, g_strerror (errno)) << endmsg;
3694 Session::restore_history (string snapshot_name)
3698 if (snapshot_name.empty()) {
3699 snapshot_name = _current_snapshot_name;
3702 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3703 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3705 info << "Loading history from " << xml_path << endmsg;
3707 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3708 info << string_compose (_("%1: no history file \"%2\" for this session."),
3709 _name, xml_path) << endmsg;
3713 if (!tree.read (xml_path)) {
3714 error << string_compose (_("Could not understand session history file \"%1\""),
3715 xml_path) << endmsg;
3722 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3725 UndoTransaction* ut = new UndoTransaction ();
3728 ut->set_name(t->property("name")->value());
3729 stringstream ss(t->property("tv-sec")->value());
3731 ss.str(t->property("tv-usec")->value());
3733 ut->set_timestamp(tv);
3735 for (XMLNodeConstIterator child_it = t->children().begin();
3736 child_it != t->children().end(); child_it++)
3738 XMLNode *n = *child_it;
3741 if (n->name() == "MementoCommand" ||
3742 n->name() == "MementoUndoCommand" ||
3743 n->name() == "MementoRedoCommand") {
3745 if ((c = memento_command_factory(n))) {
3749 } else if (n->name() == "NoteDiffCommand") {
3750 PBD::ID id (n->property("midi-source")->value());
3751 boost::shared_ptr<MidiSource> midi_source =
3752 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3754 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3756 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3759 } else if (n->name() == "SysExDiffCommand") {
3761 PBD::ID id (n->property("midi-source")->value());
3762 boost::shared_ptr<MidiSource> midi_source =
3763 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3765 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3767 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3770 } else if (n->name() == "PatchChangeDiffCommand") {
3772 PBD::ID id (n->property("midi-source")->value());
3773 boost::shared_ptr<MidiSource> midi_source =
3774 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3776 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3778 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3781 } else if (n->name() == "StatefulDiffCommand") {
3782 if ((c = stateful_diff_command_factory (n))) {
3783 ut->add_command (c);
3786 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3797 Session::config_changed (std::string p, bool ours)
3803 if (p == "seamless-loop") {
3805 } else if (p == "rf-speed") {
3807 } else if (p == "auto-loop") {
3809 } else if (p == "auto-input") {
3811 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3812 /* auto-input only makes a difference if we're rolling */
3813 set_track_monitor_input_status (!config.get_auto_input());
3816 } else if (p == "punch-in") {
3820 if ((location = _locations->auto_punch_location()) != 0) {
3822 if (config.get_punch_in ()) {
3823 replace_event (SessionEvent::PunchIn, location->start());
3825 remove_event (location->start(), SessionEvent::PunchIn);
3829 } else if (p == "punch-out") {
3833 if ((location = _locations->auto_punch_location()) != 0) {
3835 if (config.get_punch_out()) {
3836 replace_event (SessionEvent::PunchOut, location->end());
3838 clear_events (SessionEvent::PunchOut);
3842 } else if (p == "edit-mode") {
3844 Glib::Threads::Mutex::Lock lm (playlists->lock);
3846 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3847 (*i)->set_edit_mode (Config->get_edit_mode ());
3850 } else if (p == "use-video-sync") {
3852 waiting_for_sync_offset = config.get_use_video_sync();
3854 } else if (p == "mmc-control") {
3856 //poke_midi_thread ();
3858 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3860 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3862 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3864 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3866 } else if (p == "midi-control") {
3868 //poke_midi_thread ();
3870 } else if (p == "raid-path") {
3872 setup_raid_path (config.get_raid_path());
3874 } else if (p == "timecode-format") {
3878 } else if (p == "video-pullup") {
3882 } else if (p == "seamless-loop") {
3884 if (play_loop && transport_rolling()) {
3885 // to reset diskstreams etc
3886 request_play_loop (true);
3889 } else if (p == "rf-speed") {
3891 cumulative_rf_motion = 0;
3894 } else if (p == "click-sound") {
3896 setup_click_sounds (1);
3898 } else if (p == "click-emphasis-sound") {
3900 setup_click_sounds (-1);
3902 } else if (p == "clicking") {
3904 if (Config->get_clicking()) {
3905 if (_click_io && click_data) { // don't require emphasis data
3912 } else if (p == "click-gain") {
3915 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3918 } else if (p == "send-mtc") {
3920 if (Config->get_send_mtc ()) {
3921 /* mark us ready to send */
3922 next_quarter_frame_to_send = 0;
3925 } else if (p == "send-mmc") {
3927 _mmc->enable_send (Config->get_send_mmc ());
3929 } else if (p == "midi-feedback") {
3931 session_midi_feedback = Config->get_midi_feedback();
3933 } else if (p == "jack-time-master") {
3935 engine().reset_timebase ();
3937 } else if (p == "native-file-header-format") {
3939 if (!first_file_header_format_reset) {
3940 reset_native_file_format ();
3943 first_file_header_format_reset = false;
3945 } else if (p == "native-file-data-format") {
3947 if (!first_file_data_format_reset) {
3948 reset_native_file_format ();
3951 first_file_data_format_reset = false;
3953 } else if (p == "external-sync") {
3954 if (!config.get_external_sync()) {
3955 drop_sync_source ();
3957 switch_to_sync_source (Config->get_sync_source());
3959 } else if (p == "denormal-model") {
3961 } else if (p == "history-depth") {
3962 set_history_depth (Config->get_history_depth());
3963 } else if (p == "remote-model") {
3964 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3967 } else if (p == "initial-program-change") {
3969 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3972 buf[0] = MIDI::program; // channel zero by default
3973 buf[1] = (Config->get_initial_program_change() & 0x7f);
3975 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3977 } else if (p == "solo-mute-override") {
3978 // catch_up_on_solo_mute_override ();
3979 } else if (p == "listen-position" || p == "pfl-position") {
3980 listen_position_changed ();
3981 } else if (p == "solo-control-is-listen-control") {
3982 solo_control_mode_changed ();
3983 } else if (p == "solo-mute-gain") {
3984 _solo_cut_control->Changed (true, Controllable::NoGroup);
3985 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3986 last_timecode_valid = false;
3987 } else if (p == "playback-buffer-seconds") {
3988 AudioSource::allocate_working_buffers (frame_rate());
3989 } else if (p == "ltc-source-port") {
3990 reconnect_ltc_input ();
3991 } else if (p == "ltc-sink-port") {
3992 reconnect_ltc_output ();
3993 } else if (p == "timecode-generator-offset") {
3994 ltc_tx_parse_offset();
3995 } else if (p == "auto-return-target-list") {
3996 follow_playhead_priority ();
4003 Session::set_history_depth (uint32_t d)
4005 _history.set_depth (d);
4009 Session::load_diskstreams_2X (XMLNode const & node, int)
4012 XMLNodeConstIterator citer;
4014 clist = node.children();
4016 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4019 /* diskstreams added automatically by DiskstreamCreated handler */
4020 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4021 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4022 _diskstreams_2X.push_back (dsp);
4024 error << _("Session: unknown diskstream type in XML") << endmsg;
4028 catch (failed_constructor& err) {
4029 error << _("Session: could not load diskstream via XML state") << endmsg;
4037 /** Connect things to the MMC object */
4039 Session::setup_midi_machine_control ()
4041 _mmc = new MIDI::MachineControl;
4043 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4044 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4046 if (!async_out || !async_out) {
4050 /* XXXX argh, passing raw pointers back into libmidi++ */
4052 MIDI::Port* mmc_in = async_in.get();
4053 MIDI::Port* mmc_out = async_out.get();
4055 _mmc->set_ports (mmc_in, mmc_out);
4057 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4058 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4059 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4060 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4061 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4062 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4063 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4064 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4065 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4066 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4067 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4068 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4069 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4071 /* also handle MIDI SPP because its so common */
4073 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4074 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4075 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4078 boost::shared_ptr<Controllable>
4079 Session::solo_cut_control() const
4081 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4082 controls in Ardour that currently get presented to the user in the GUI that require
4083 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4085 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4086 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4090 return _solo_cut_control;
4094 Session::save_snapshot_name (const std::string & n)
4096 /* assure Stateful::_instant_xml is loaded
4097 * add_instant_xml() only adds to existing data and defaults
4098 * to use an empty Tree otherwise
4100 instant_xml ("LastUsedSnapshot");
4102 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4103 last_used_snapshot->add_property ("name", string(n));
4104 add_instant_xml (*last_used_snapshot, false);
4108 Session::set_snapshot_name (const std::string & n)
4110 _current_snapshot_name = n;
4111 save_snapshot_name (n);
4115 Session::rename (const std::string& new_name)
4117 string legal_name = legalize_for_path (new_name);
4123 string const old_sources_root = _session_dir->sources_root();
4125 if (!_writable || (_state_of_the_state & CannotSave)) {
4126 error << _("Cannot rename read-only session.") << endmsg;
4127 return 0; // don't show "messed up" warning
4129 if (record_status() == Recording) {
4130 error << _("Cannot rename session while recording") << endmsg;
4131 return 0; // don't show "messed up" warning
4134 StateProtector stp (this);
4139 * interchange subdirectory
4143 * Backup files are left unchanged and not renamed.
4146 /* Windows requires that we close all files before attempting the
4147 * rename. This works on other platforms, but isn't necessary there.
4148 * Leave it in place for all platforms though, since it may help
4149 * catch issues that could arise if the way Source files work ever
4150 * change (since most developers are not using Windows).
4153 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4154 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4160 /* pass one: not 100% safe check that the new directory names don't
4164 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4168 /* this is a stupid hack because Glib::path_get_dirname() is
4169 * lexical-only, and so passing it /a/b/c/ gives a different
4170 * result than passing it /a/b/c ...
4173 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4174 oldstr = oldstr.substr (0, oldstr.length() - 1);
4177 string base = Glib::path_get_dirname (oldstr);
4179 newstr = Glib::build_filename (base, legal_name);
4181 cerr << "Looking for " << newstr << endl;
4183 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4184 cerr << " exists\n";
4193 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4199 /* this is a stupid hack because Glib::path_get_dirname() is
4200 * lexical-only, and so passing it /a/b/c/ gives a different
4201 * result than passing it /a/b/c ...
4204 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4205 oldstr = oldstr.substr (0, oldstr.length() - 1);
4208 string base = Glib::path_get_dirname (oldstr);
4209 newstr = Glib::build_filename (base, legal_name);
4211 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4213 cerr << "Rename " << oldstr << " => " << newstr << endl;
4214 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4215 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4216 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4220 /* Reset path in "session dirs" */
4225 /* reset primary SessionDirectory object */
4228 (*_session_dir) = newstr;
4233 /* now rename directory below session_dir/interchange */
4235 string old_interchange_dir;
4236 string new_interchange_dir;
4238 /* use newstr here because we renamed the path
4239 * (folder/directory) that used to be oldstr to newstr above
4242 v.push_back (newstr);
4243 v.push_back (interchange_dir_name);
4244 v.push_back (Glib::path_get_basename (oldstr));
4246 old_interchange_dir = Glib::build_filename (v);
4249 v.push_back (newstr);
4250 v.push_back (interchange_dir_name);
4251 v.push_back (legal_name);
4253 new_interchange_dir = Glib::build_filename (v);
4255 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4257 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4258 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4259 old_interchange_dir, new_interchange_dir,
4262 error << string_compose (_("renaming %s as %2 failed (%3)"),
4263 old_interchange_dir, new_interchange_dir,
4272 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4273 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4275 cerr << "Rename " << oldstr << " => " << newstr << endl;
4277 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4278 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4279 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4285 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4287 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4288 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4290 cerr << "Rename " << oldstr << " => " << newstr << endl;
4292 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4293 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4294 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4299 /* remove old name from recent sessions */
4300 remove_recent_sessions (_path);
4303 /* update file source paths */
4305 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4306 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4308 string p = fs->path ();
4309 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4311 SourceFactory::setup_peakfile(i->second, true);
4315 set_snapshot_name (new_name);
4320 /* save state again to get everything just right */
4322 save_state (_current_snapshot_name);
4324 /* add to recent sessions */
4326 store_recent_sessions (new_name, _path);
4332 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4334 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4338 if (!tree.read (xmlpath)) {
4346 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4349 bool found_sr = false;
4350 bool found_data_format = false;
4352 if (get_session_info_from_path (tree, xmlpath)) {
4358 XMLProperty const * prop;
4359 XMLNode const * root (tree.root());
4361 if ((prop = root->property (X_("sample-rate"))) != 0) {
4362 sample_rate = atoi (prop->value());
4366 const XMLNodeList& children (root->children());
4367 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4368 const XMLNode* child = *c;
4369 if (child->name() == "Config") {
4370 const XMLNodeList& options (child->children());
4371 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4372 XMLNode const * option = *oc;
4373 XMLProperty const * name = option->property("name");
4379 if (name->value() == "native-file-data-format") {
4380 XMLProperty const * value = option->property ("value");
4382 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4384 found_data_format = true;
4390 if (found_data_format) {
4395 return !(found_sr && found_data_format); // zero if they are both found
4399 Session::get_snapshot_from_instant (const std::string& session_dir)
4401 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4403 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4408 if (!tree.read (instant_xml_path)) {
4412 XMLProperty const * prop;
4413 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4414 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4415 return prop->value();
4421 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4422 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4425 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4429 SourcePathMap source_path_map;
4431 boost::shared_ptr<AudioFileSource> afs;
4436 Glib::Threads::Mutex::Lock lm (source_lock);
4438 cerr << " total sources = " << sources.size();
4440 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4441 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4447 if (fs->within_session()) {
4451 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4452 source_path_map[fs->path()].push_back (fs);
4454 SeveralFileSources v;
4456 source_path_map.insert (make_pair (fs->path(), v));
4462 cerr << " fsources = " << total << endl;
4464 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4466 /* tell caller where we are */
4468 string old_path = i->first;
4470 callback (n, total, old_path);
4472 cerr << old_path << endl;
4476 switch (i->second.front()->type()) {
4477 case DataType::AUDIO:
4478 new_path = new_audio_source_path_for_embedded (old_path);
4481 case DataType::MIDI:
4482 /* XXX not implemented yet */
4486 if (new_path.empty()) {
4490 cerr << "Move " << old_path << " => " << new_path << endl;
4492 if (!copy_file (old_path, new_path)) {
4493 cerr << "failed !\n";
4497 /* make sure we stop looking in the external
4498 dir/folder. Remember, this is an all-or-nothing
4499 operations, it doesn't merge just some files.
4501 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4503 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4504 (*f)->set_path (new_path);
4509 save_state ("", false, false);
4515 bool accept_all_files (string const &, void *)
4521 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4523 /* 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.
4528 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4530 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4532 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4534 v.push_back (new_session_folder); /* full path */
4535 v.push_back (interchange_dir_name);
4536 v.push_back (new_session_path); /* just one directory/folder */
4537 v.push_back (typedir);
4538 v.push_back (Glib::path_get_basename (old_path));
4540 return Glib::build_filename (v);
4544 Session::save_as (SaveAs& saveas)
4546 vector<string> files;
4547 string current_folder = Glib::path_get_dirname (_path);
4548 string new_folder = legalize_for_path (saveas.new_name);
4549 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4550 int64_t total_bytes = 0;
4554 int32_t internal_file_cnt = 0;
4556 vector<string> do_not_copy_extensions;
4557 do_not_copy_extensions.push_back (statefile_suffix);
4558 do_not_copy_extensions.push_back (pending_suffix);
4559 do_not_copy_extensions.push_back (backup_suffix);
4560 do_not_copy_extensions.push_back (temp_suffix);
4561 do_not_copy_extensions.push_back (history_suffix);
4563 /* get total size */
4565 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4567 /* need to clear this because
4568 * find_files_matching_filter() is cumulative
4573 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4575 all += files.size();
4577 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4579 g_stat ((*i).c_str(), &gsb);
4580 total_bytes += gsb.st_size;
4584 /* save old values so we can switch back if we are not switching to the new session */
4586 string old_path = _path;
4587 string old_name = _name;
4588 string old_snapshot = _current_snapshot_name;
4589 string old_sd = _session_dir->root_path();
4590 vector<string> old_search_path[DataType::num_types];
4591 string old_config_search_path[DataType::num_types];
4593 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4594 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4595 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4596 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4598 /* switch session directory */
4600 (*_session_dir) = to_dir;
4602 /* create new tree */
4604 if (!_session_dir->create()) {
4605 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4610 /* copy all relevant files. Find each location in session_dirs,
4611 * and copy files from there to target.
4614 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4616 /* need to clear this because
4617 * find_files_matching_filter() is cumulative
4622 const size_t prefix_len = (*sd).path.size();
4624 /* Work just on the files within this session dir */
4626 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4628 /* add dir separator to protect against collisions with
4629 * track names (e.g. track named "audiofiles" or
4633 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4634 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4635 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4637 /* copy all the files. Handling is different for media files
4638 than others because of the *silly* subtree we have below the interchange
4639 folder. That really was a bad idea, but I'm not fixing it as part of
4640 implementing ::save_as().
4643 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4645 std::string from = *i;
4648 string filename = Glib::path_get_basename (from);
4649 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4650 if (filename == ".DS_STORE") {
4655 if (from.find (audiofile_dir_string) != string::npos) {
4657 /* audio file: only copy if asked */
4659 if (saveas.include_media && saveas.copy_media) {
4661 string to = make_new_media_path (*i, to_dir, new_folder);
4663 info << "media file copying from " << from << " to " << to << endmsg;
4665 if (!copy_file (from, to)) {
4666 throw Glib::FileError (Glib::FileError::IO_ERROR,
4667 string_compose(_("\ncopying \"%1\" failed !"), from));
4671 /* we found media files inside the session folder */
4673 internal_file_cnt++;
4675 } else if (from.find (midifile_dir_string) != string::npos) {
4677 /* midi file: always copy unless
4678 * creating an empty new session
4681 if (saveas.include_media) {
4683 string to = make_new_media_path (*i, to_dir, new_folder);
4685 info << "media file copying from " << from << " to " << to << endmsg;
4687 if (!copy_file (from, to)) {
4688 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4692 /* we found media files inside the session folder */
4694 internal_file_cnt++;
4696 } else if (from.find (analysis_dir_string) != string::npos) {
4698 /* make sure analysis dir exists in
4699 * new session folder, but we're not
4700 * copying analysis files here, see
4704 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4709 /* normal non-media file. Don't copy state, history, etc.
4712 bool do_copy = true;
4714 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4715 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4716 /* end of filename matches extension, do not copy file */
4722 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4723 /* don't copy peakfiles if
4724 * we're not copying media
4730 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4732 info << "attempting to make directory/folder " << to << endmsg;
4734 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4735 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4738 info << "attempting to copy " << from << " to " << to << endmsg;
4740 if (!copy_file (from, to)) {
4741 throw Glib::FileError (Glib::FileError::IO_ERROR,
4742 string_compose(_("\ncopying \"%1\" failed !"), from));
4747 /* measure file size even if we're not going to copy so that our Progress
4748 signals are correct, since we included these do-not-copy files
4749 in the computation of the total size and file count.
4753 g_stat (from.c_str(), &gsb);
4754 copied += gsb.st_size;
4757 double fraction = (double) copied / total_bytes;
4759 bool keep_going = true;
4761 if (saveas.copy_media) {
4763 /* no need or expectation of this if
4764 * media is not being copied, because
4765 * it will be fast(ish).
4768 /* tell someone "X percent, file M of N"; M is one-based */
4770 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4778 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4784 /* copy optional folders, if any */
4786 string old = plugins_dir ();
4787 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4788 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4789 copy_files (old, newdir);
4792 old = externals_dir ();
4793 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4794 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4795 copy_files (old, newdir);
4798 old = automation_dir ();
4799 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4800 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4801 copy_files (old, newdir);
4804 if (saveas.include_media) {
4806 if (saveas.copy_media) {
4807 #ifndef PLATFORM_WINDOWS
4808 /* There are problems with analysis files on
4809 * Windows, because they used a colon in their
4810 * names as late as 4.0. Colons are not legal
4811 * under Windows even if NTFS allows them.
4813 * This is a tricky problem to solve so for
4814 * just don't copy these files. They will be
4815 * regenerated as-needed anyway, subject to the
4816 * existing issue that the filenames will be
4817 * rejected by Windows, which is a separate
4818 * problem (though related).
4821 /* only needed if we are copying media, since the
4822 * analysis data refers to media data
4825 old = analysis_dir ();
4826 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4827 string newdir = Glib::build_filename (to_dir, "analysis");
4828 copy_files (old, newdir);
4830 #endif /* PLATFORM_WINDOWS */
4836 set_snapshot_name (saveas.new_name);
4837 _name = saveas.new_name;
4839 if (saveas.include_media && !saveas.copy_media) {
4841 /* reset search paths of the new session (which we're pretending to be right now) to
4842 include the original session search path, so we can still find all audio.
4845 if (internal_file_cnt) {
4846 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4847 ensure_search_path_includes (*s, DataType::AUDIO);
4848 cerr << "be sure to include " << *s << " for audio" << endl;
4851 /* we do not do this for MIDI because we copy
4852 all MIDI files if saveas.include_media is
4858 bool was_dirty = dirty ();
4860 save_state ("", false, false, !saveas.include_media);
4861 save_default_options ();
4863 if (saveas.copy_media && saveas.copy_external) {
4864 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4865 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4869 saveas.final_session_folder_name = _path;
4871 store_recent_sessions (_name, _path);
4873 if (!saveas.switch_to) {
4875 /* switch back to the way things were */
4879 set_snapshot_name (old_snapshot);
4881 (*_session_dir) = old_sd;
4887 if (internal_file_cnt) {
4888 /* reset these to their original values */
4889 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4890 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4895 /* prune session dirs, and update disk space statistics
4900 session_dirs.clear ();
4901 session_dirs.push_back (sp);
4902 refresh_disk_space ();
4904 /* ensure that all existing tracks reset their current capture source paths
4906 reset_write_sources (true, true);
4908 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4909 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4912 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4913 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4919 if (fs->within_session()) {
4920 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4921 fs->set_path (newpath);
4926 } catch (Glib::FileError& e) {
4928 saveas.failure_message = e.what();
4930 /* recursively remove all the directories */
4932 remove_directory (to_dir);
4940 saveas.failure_message = _("unknown reason");
4942 /* recursively remove all the directories */
4944 remove_directory (to_dir);
4954 static void set_progress (Progress* p, size_t n, size_t t)
4956 p->set_progress (float (n) / float(t));
4960 Session::archive_session (const std::string& dest,
4961 const std::string& name,
4962 ArchiveEncode compress_audio,
4963 bool only_used_sources,
4966 if (dest.empty () || name.empty ()) {
4970 /* save current values */
4971 bool was_dirty = dirty ();
4972 string old_path = _path;
4973 string old_name = _name;
4974 string old_snapshot = _current_snapshot_name;
4975 string old_sd = _session_dir->root_path();
4976 string old_config_search_path[DataType::num_types];
4977 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4978 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4980 /* ensure that session-path is included in search-path */
4982 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4983 if ((*sd).path == old_path) {
4991 /* create temporary dir to save session to */
4992 #ifdef PLATFORM_WINDOWS
4993 char tmp[256] = "C:\\TEMP\\";
4994 GetTempPath (sizeof (tmp), tmp);
4996 char const* tmp = getenv("TMPDIR");
5001 if ((strlen (tmp) + 21) > 1024) {
5006 strcpy (tmptpl, tmp);
5007 strcat (tmptpl, "ardourarchive-XXXXXX");
5008 char* tmpdir = g_mkdtemp (tmptpl);
5014 std::string to_dir = std::string (tmpdir);
5016 /* switch session directory temporarily */
5017 (*_session_dir) = to_dir;
5019 if (!_session_dir->create()) {
5020 (*_session_dir) = old_sd;
5021 remove_directory (to_dir);
5025 /* prepare archive */
5026 string archive = Glib::build_filename (dest, name + ".tar.xz");
5028 PBD::ScopedConnectionList progress_connection;
5029 PBD::FileArchive ar (archive);
5031 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5034 /* collect files to archive */
5035 std::map<string,string> filemap;
5037 vector<string> do_not_copy_extensions;
5038 do_not_copy_extensions.push_back (statefile_suffix);
5039 do_not_copy_extensions.push_back (pending_suffix);
5040 do_not_copy_extensions.push_back (backup_suffix);
5041 do_not_copy_extensions.push_back (temp_suffix);
5042 do_not_copy_extensions.push_back (history_suffix);
5044 vector<string> blacklist_dirs;
5045 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5046 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5047 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5048 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5049 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5050 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5052 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5054 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5055 if (only_used_sources) {
5056 playlists->sync_all_regions_with_regions ();
5057 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5060 // collect audio sources for this session, calc total size for encoding
5061 // add option to only include *used* sources (see Session::cleanup_sources)
5062 size_t total_size = 0;
5064 Glib::Threads::Mutex::Lock lm (source_lock);
5065 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5066 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5067 if (!afs || afs->readable_length () == 0) {
5071 if (only_used_sources) {
5075 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5080 std::string from = afs->path();
5082 if (compress_audio != NO_ENCODE) {
5083 total_size += afs->readable_length ();
5085 if (afs->within_session()) {
5086 filemap[from] = make_new_media_path (from, name, name);
5088 filemap[from] = make_new_media_path (from, name, name);
5089 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5096 if (compress_audio != NO_ENCODE) {
5098 progress->set_progress (2); // set to "encoding"
5099 progress->set_progress (0);
5102 Glib::Threads::Mutex::Lock lm (source_lock);
5103 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5104 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5105 if (!afs || afs->readable_length () == 0) {
5109 if (only_used_sources) {
5113 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5118 orig_sources[afs] = afs->path();
5120 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5121 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5122 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5125 progress->descend ((float)afs->readable_length () / total_size);
5129 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5130 afs->replace_file (new_path);
5133 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5137 progress->ascend ();
5143 progress->set_progress (-1); // set to "archiving"
5144 progress->set_progress (0);
5147 /* index files relevant for this session */
5148 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5149 vector<string> files;
5151 size_t prefix_len = (*sd).path.size();
5152 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5156 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5158 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5159 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5160 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5162 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5163 std::string from = *i;
5166 string filename = Glib::path_get_basename (from);
5167 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5168 if (filename == ".DS_STORE") {
5173 if (from.find (audiofile_dir_string) != string::npos) {
5175 } else if (from.find (midifile_dir_string) != string::npos) {
5176 filemap[from] = make_new_media_path (from, name, name);
5177 } else if (from.find (videofile_dir_string) != string::npos) {
5178 filemap[from] = make_new_media_path (from, name, name);
5180 bool do_copy = true;
5181 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5182 if (from.find (*v) != string::npos) {
5187 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5188 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5195 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5201 /* write session file */
5203 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5205 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5207 save_default_options ();
5209 size_t prefix_len = _path.size();
5210 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5214 /* collect session-state files */
5215 vector<string> files;
5216 do_not_copy_extensions.clear ();
5217 do_not_copy_extensions.push_back (history_suffix);
5219 blacklist_dirs.clear ();
5220 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5222 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5223 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5224 std::string from = *i;
5225 bool do_copy = true;
5226 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5227 if (from.find (*v) != string::npos) {
5232 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5233 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5239 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5243 /* restore original values */
5246 set_snapshot_name (old_snapshot);
5247 (*_session_dir) = old_sd;
5251 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5252 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5254 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5255 i->first->replace_file (i->second);
5258 int rv = ar.create (filemap);
5259 remove_directory (to_dir);
5265 Session::undo (uint32_t n)
5267 if (actively_recording()) {
5275 Session::redo (uint32_t n)
5277 if (actively_recording()) {