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"
96 #include "ardour/lv2_plugin.h"
98 #include "ardour/midi_model.h"
99 #include "ardour/midi_patch_manager.h"
100 #include "ardour/midi_region.h"
101 #include "ardour/midi_scene_changer.h"
102 #include "ardour/midi_source.h"
103 #include "ardour/midi_track.h"
104 #include "ardour/pannable.h"
105 #include "ardour/playlist_factory.h"
106 #include "ardour/playlist_source.h"
107 #include "ardour/port.h"
108 #include "ardour/processor.h"
109 #include "ardour/progress.h"
110 #include "ardour/profile.h"
111 #include "ardour/proxy_controllable.h"
112 #include "ardour/recent_sessions.h"
113 #include "ardour/region_factory.h"
114 #include "ardour/revision.h"
115 #include "ardour/route_group.h"
116 #include "ardour/send.h"
117 #include "ardour/session.h"
118 #include "ardour/session_directory.h"
119 #include "ardour/session_metadata.h"
120 #include "ardour/session_playlists.h"
121 #include "ardour/session_state_utils.h"
122 #include "ardour/silentfilesource.h"
123 #include "ardour/sndfilesource.h"
124 #include "ardour/source_factory.h"
125 #include "ardour/speakers.h"
126 #include "ardour/template_utils.h"
127 #include "ardour/tempo.h"
128 #include "ardour/ticker.h"
129 #include "ardour/user_bundle.h"
130 #include "ardour/vca.h"
131 #include "ardour/vca_manager.h"
133 #include "control_protocol/control_protocol.h"
135 #include "LuaBridge/LuaBridge.h"
137 #include "pbd/i18n.h"
141 using namespace ARDOUR;
144 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
147 Session::pre_engine_init (string fullpath)
149 if (fullpath.empty()) {
151 throw failed_constructor();
154 /* discover canonical fullpath */
156 _path = canonical_path(fullpath);
159 if (Profile->get_trx() ) {
160 // Waves TracksLive has a usecase of session replacement with a new one.
161 // We should check session state file (<session_name>.ardour) existance
162 // to determine if the session is new or not
164 string full_session_name = Glib::build_filename( fullpath, _name );
165 full_session_name += statefile_suffix;
167 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
169 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
172 /* finish initialization that can't be done in a normal C++ constructor
176 timerclear (&last_mmc_step);
177 g_atomic_int_set (&processing_prohibited, 0);
178 g_atomic_int_set (&_record_status, Disabled);
179 g_atomic_int_set (&_playback_load, 100);
180 g_atomic_int_set (&_capture_load, 100);
182 _all_route_group->set_active (true, this);
183 interpolation.add_channel_to (0, 0);
185 if (config.get_use_video_sync()) {
186 waiting_for_sync_offset = true;
188 waiting_for_sync_offset = false;
191 last_rr_session_dir = session_dirs.begin();
193 set_history_depth (Config->get_history_depth());
195 /* default: assume simple stereo speaker configuration */
197 _speakers->setup_default_speakers (2);
199 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
200 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
201 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
202 add_controllable (_solo_cut_control);
204 /* These are all static "per-class" signals */
206 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
207 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
208 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
209 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
210 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
212 /* stop IO objects from doing stuff until we're ready for them */
214 Delivery::disable_panners ();
215 IO::disable_connecting ();
219 Session::post_engine_init ()
221 BootMessage (_("Set block size and sample rate"));
223 set_block_size (_engine.samples_per_cycle());
224 set_frame_rate (_engine.sample_rate());
226 BootMessage (_("Using configuration"));
228 _midi_ports = new MidiPortManager;
230 MIDISceneChanger* msc;
232 _scene_changer = msc = new MIDISceneChanger (*this);
233 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
234 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
236 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
237 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
239 setup_midi_machine_control ();
241 if (_butler->start_thread()) {
242 error << _("Butler did not start") << endmsg;
246 if (start_midi_thread ()) {
247 error << _("MIDI I/O thread did not start") << endmsg;
251 setup_click_sounds (0);
252 setup_midi_control ();
254 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
255 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
258 /* tempo map requires sample rate knowledge */
261 _tempo_map = new TempoMap (_current_frame_rate);
262 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
263 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::gui_tempo_map_changed, this));
265 /* MidiClock requires a tempo map */
268 midi_clock = new MidiClockTicker ();
269 midi_clock->set_session (this);
271 /* crossfades require sample rate knowledge */
273 SndFileSource::setup_standard_crossfades (*this, frame_rate());
274 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
275 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
277 AudioDiskstream::allocate_working_buffers();
278 refresh_disk_space ();
280 /* we're finally ready to call set_state() ... all objects have
281 * been created, the engine is running.
285 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
286 error << _("Could not set session state from XML") << endmsg;
290 // set_state() will call setup_raid_path(), but if it's a new session we need
291 // to call setup_raid_path() here.
292 setup_raid_path (_path);
297 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
298 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
300 Config->map_parameters (ff);
301 config.map_parameters (ft);
302 _butler->map_parameters ();
304 /* Reset all panners */
306 Delivery::reset_panners ();
308 /* this will cause the CPM to instantiate any protocols that are in use
309 * (or mandatory), which will pass it this Session, and then call
310 * set_state() on each instantiated protocol to match stored state.
313 ControlProtocolManager::instance().set_session (this);
315 /* This must be done after the ControlProtocolManager set_session above,
316 as it will set states for ports which the ControlProtocolManager creates.
319 // XXX set state of MIDI::Port's
320 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
322 /* And this must be done after the MIDI::Manager::set_port_states as
323 * it will try to make connections whose details are loaded by set_port_states.
328 /* Let control protocols know that we are now all connected, so they
329 * could start talking to surfaces if they want to.
332 ControlProtocolManager::instance().midi_connectivity_established ();
334 if (_is_new && !no_auto_connect()) {
335 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
336 auto_connect_master_bus ();
339 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
341 /* update latencies */
343 initialize_latencies ();
345 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
346 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
347 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
349 } catch (AudioEngine::PortRegistrationFailure& err) {
350 /* handle this one in a different way than all others, so that its clear what happened */
351 error << err.what() << endmsg;
353 } catch (std::exception const & e) {
354 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
357 error << _("Unknown exception during session setup") << endmsg;
361 BootMessage (_("Reset Remote Controls"));
363 // send_full_time_code (0);
364 _engine.transport_locate (0);
366 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
367 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
369 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
372 /* initial program change will be delivered later; see ::config_changed() */
374 _state_of_the_state = Clean;
376 Port::set_connecting_blocked (false);
378 DirtyChanged (); /* EMIT SIGNAL */
382 } else if (state_was_pending) {
384 remove_pending_capture_state ();
385 state_was_pending = false;
388 /* Now, finally, we can fill the playback buffers */
390 BootMessage (_("Filling playback buffers"));
392 boost::shared_ptr<RouteList> rl = routes.reader();
393 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
394 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
395 if (trk && !trk->hidden()) {
396 trk->seek (_transport_frame, true);
404 Session::session_loaded ()
408 _state_of_the_state = Clean;
410 DirtyChanged (); /* EMIT SIGNAL */
414 } else if (state_was_pending) {
416 remove_pending_capture_state ();
417 state_was_pending = false;
420 /* Now, finally, we can fill the playback buffers */
422 BootMessage (_("Filling playback buffers"));
423 force_locate (_transport_frame, false);
427 Session::raid_path () const
429 Searchpath raid_search_path;
431 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
432 raid_search_path += (*i).path;
435 return raid_search_path.to_string ();
439 Session::setup_raid_path (string path)
448 session_dirs.clear ();
450 Searchpath search_path(path);
451 Searchpath sound_search_path;
452 Searchpath midi_search_path;
454 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
456 sp.blocks = 0; // not needed
457 session_dirs.push_back (sp);
459 SessionDirectory sdir(sp.path);
461 sound_search_path += sdir.sound_path ();
462 midi_search_path += sdir.midi_path ();
465 // reset the round-robin soundfile path thingie
466 last_rr_session_dir = session_dirs.begin();
470 Session::path_is_within_session (const std::string& path)
472 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
473 if (PBD::path_is_within (i->path, path)) {
481 Session::ensure_subdirs ()
485 dir = session_directory().peak_path();
487 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
488 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
492 dir = session_directory().sound_path();
494 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
495 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
499 dir = session_directory().midi_path();
501 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
502 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 dir = session_directory().dead_path();
508 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
509 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
513 dir = session_directory().export_path();
515 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
516 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
520 dir = analysis_dir ();
522 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
523 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
527 dir = plugins_dir ();
529 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
530 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
534 dir = externals_dir ();
536 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
537 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
544 /** @param session_template directory containing session template, or empty.
545 * Caller must not hold process lock.
548 Session::create (const string& session_template, BusProfile* bus_profile)
550 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
551 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
555 if (ensure_subdirs ()) {
559 _writable = exists_and_writable (_path);
561 if (!session_template.empty()) {
562 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
564 FILE* in = g_fopen (in_path.c_str(), "rb");
567 /* no need to call legalize_for_path() since the string
568 * in session_template is already a legal path name
570 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
572 FILE* out = g_fopen (out_path.c_str(), "wb");
576 stringstream new_session;
579 size_t charsRead = fread (buf, sizeof(char), 1024, in);
582 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
587 if (charsRead == 0) {
590 new_session.write (buf, charsRead);
594 string file_contents = new_session.str();
595 size_t writeSize = file_contents.length();
596 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
597 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
605 if (!ARDOUR::Profile->get_trx()) {
606 /* Copy plugin state files from template to new session */
607 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
608 copy_recurse (template_plugins, plugins_dir ());
614 error << string_compose (_("Could not open %1 for writing session template"), out_path)
621 error << string_compose (_("Could not open session template %1 for reading"), in_path)
628 if (Profile->get_trx()) {
630 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
631 Remember that this is a brand new session. Sessions
632 loaded from saved state will get this range from the saved state.
635 set_session_range_location (0, 0);
637 /* Initial loop location, from absolute zero, length 10 seconds */
639 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
640 _locations->add (loc, true);
641 set_auto_loop_location (loc);
644 _state_of_the_state = Clean;
646 /* set up Master Out and Monitor Out if necessary */
651 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
653 // Waves Tracks: always create master bus for Tracks
654 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
655 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
663 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
664 r->input()->ensure_io (count, false, this);
665 r->output()->ensure_io (count, false, this);
671 /* prohibit auto-connect to master, because there isn't one */
672 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
676 add_routes (rl, false, false, false, PresentationInfo::max_order);
679 // Waves Tracks: Skip this. Always use autoconnection for Tracks
680 if (!ARDOUR::Profile->get_trx()) {
682 /* this allows the user to override settings with an environment variable.
685 if (no_auto_connect()) {
686 bus_profile->input_ac = AutoConnectOption (0);
687 bus_profile->output_ac = AutoConnectOption (0);
690 Config->set_input_auto_connect (bus_profile->input_ac);
691 Config->set_output_auto_connect (bus_profile->output_ac);
695 if (Config->get_use_monitor_bus() && bus_profile) {
696 add_monitor_section ();
703 Session::maybe_write_autosave()
705 if (dirty() && record_status() != Recording) {
706 save_state("", true);
711 Session::remove_pending_capture_state ()
713 std::string pending_state_file_path(_session_dir->root_path());
715 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
717 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
719 if (g_remove (pending_state_file_path.c_str()) != 0) {
720 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
721 pending_state_file_path, g_strerror (errno)) << endmsg;
725 /** Rename a state file.
726 * @param old_name Old snapshot name.
727 * @param new_name New snapshot name.
730 Session::rename_state (string old_name, string new_name)
732 if (old_name == _current_snapshot_name || old_name == _name) {
733 /* refuse to rename the current snapshot or the "main" one */
737 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
738 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
740 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
741 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
743 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
744 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
745 old_name, new_name, g_strerror(errno)) << endmsg;
749 /** Remove a state file.
750 * @param snapshot_name Snapshot name.
753 Session::remove_state (string snapshot_name)
755 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
756 // refuse to remove the current snapshot or the "main" one
760 std::string xml_path(_session_dir->root_path());
762 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
764 if (!create_backup_file (xml_path)) {
765 // don't remove it if a backup can't be made
766 // create_backup_file will log the error.
771 if (g_remove (xml_path.c_str()) != 0) {
772 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
773 xml_path, g_strerror (errno)) << endmsg;
777 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
779 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
781 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
784 std::string xml_path(_session_dir->root_path());
786 /* prevent concurrent saves from different threads */
788 Glib::Threads::Mutex::Lock lm (save_state_lock);
790 if (!_writable || (_state_of_the_state & CannotSave)) {
794 if (g_atomic_int_get(&_suspend_save)) {
798 _save_queued = false;
800 if (!_engine.connected ()) {
801 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
808 const int64_t save_start_time = g_get_monotonic_time();
811 /* tell sources we're saving first, in case they write out to a new file
812 * which should be saved with the state rather than the old one */
813 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
815 i->second->session_saved();
816 } catch (Evoral::SMF::FileError& e) {
817 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
821 SessionSaveUnderway (); /* EMIT SIGNAL */
823 bool mark_as_clean = true;
825 if (!snapshot_name.empty() && !switch_to_snapshot) {
826 mark_as_clean = false;
830 mark_as_clean = false;
831 tree.set_root (&get_template());
833 tree.set_root (&get_state());
836 if (snapshot_name.empty()) {
837 snapshot_name = _current_snapshot_name;
838 } else if (switch_to_snapshot) {
839 set_snapshot_name (snapshot_name);
842 assert (!snapshot_name.empty());
846 /* proper save: use statefile_suffix (.ardour in English) */
848 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
850 /* make a backup copy of the old file */
852 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
853 // create_backup_file will log the error
859 /* pending save: use pending_suffix (.pending in English) */
860 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
863 std::string tmp_path(_session_dir->root_path());
864 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
866 cerr << "actually writing state to " << tmp_path << endl;
868 if (!tree.write (tmp_path)) {
869 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
870 if (g_remove (tmp_path.c_str()) != 0) {
871 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
872 tmp_path, g_strerror (errno)) << endmsg;
878 cerr << "renaming state to " << xml_path << endl;
880 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
881 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
882 tmp_path, xml_path, g_strerror(errno)) << endmsg;
883 if (g_remove (tmp_path.c_str()) != 0) {
884 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
885 tmp_path, g_strerror (errno)) << endmsg;
893 save_history (snapshot_name);
896 bool was_dirty = dirty();
898 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
901 DirtyChanged (); /* EMIT SIGNAL */
905 StateSaved (snapshot_name); /* EMIT SIGNAL */
909 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
910 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
916 Session::restore_state (string snapshot_name)
918 if (load_state (snapshot_name) == 0) {
919 set_state (*state_tree->root(), Stateful::loading_state_version);
926 Session::load_state (string snapshot_name)
931 state_was_pending = false;
933 /* check for leftover pending state from a crashed capture attempt */
935 std::string xmlpath(_session_dir->root_path());
936 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
938 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
940 /* there is pending state from a crashed capture attempt */
942 boost::optional<int> r = AskAboutPendingState();
943 if (r.get_value_or (1)) {
944 state_was_pending = true;
948 if (!state_was_pending) {
949 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
952 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
953 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
954 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
955 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
960 state_tree = new XMLTree;
964 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
966 if (!state_tree->read (xmlpath)) {
967 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
973 XMLNode const & root (*state_tree->root());
975 if (root.name() != X_("Session")) {
976 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
982 XMLProperty const * prop;
984 if ((prop = root.property ("version")) == 0) {
985 /* no version implies very old version of Ardour */
986 Stateful::loading_state_version = 1000;
988 if (prop->value().find ('.') != string::npos) {
989 /* old school version format */
990 if (prop->value()[0] == '2') {
991 Stateful::loading_state_version = 2000;
993 Stateful::loading_state_version = 3000;
996 Stateful::loading_state_version = atoi (prop->value());
1000 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1002 std::string backup_path(_session_dir->root_path());
1003 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1004 backup_path = Glib::build_filename (backup_path, backup_filename);
1006 // only create a backup for a given statefile version once
1008 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1010 VersionMismatch (xmlpath, backup_path);
1012 if (!copy_file (xmlpath, backup_path)) {;
1018 save_snapshot_name (snapshot_name);
1024 Session::load_options (const XMLNode& node)
1027 config.set_variables (node);
1032 Session::save_default_options ()
1034 return config.save_state();
1038 Session::get_state()
1044 Session::get_template()
1046 /* if we don't disable rec-enable, diskstreams
1047 will believe they need to store their capture
1048 sources in their state node.
1051 disable_record (false);
1053 return state(false);
1057 Session::state (bool full_state)
1060 XMLNode* node = new XMLNode("Session");
1064 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1065 node->add_property("version", buf);
1067 child = node->add_child ("ProgramVersion");
1068 child->add_property("created-with", created_with);
1070 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1071 child->add_property("modified-with", modified_with);
1073 /* store configuration settings */
1077 node->add_property ("name", _name);
1078 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1079 node->add_property ("sample-rate", buf);
1081 if (session_dirs.size() > 1) {
1085 vector<space_and_path>::iterator i = session_dirs.begin();
1086 vector<space_and_path>::iterator next;
1088 ++i; /* skip the first one */
1092 while (i != session_dirs.end()) {
1096 if (next != session_dirs.end()) {
1097 p += G_SEARCHPATH_SEPARATOR;
1106 child = node->add_child ("Path");
1107 child->add_content (p);
1111 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1113 /* save the ID counter */
1115 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1116 node->add_property ("id-counter", buf);
1118 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1119 node->add_property ("name-counter", buf);
1121 /* save the event ID counter */
1123 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1124 node->add_property ("event-counter", buf);
1126 /* save the VCA counter */
1128 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1129 node->add_property ("vca-counter", buf);
1131 /* various options */
1133 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1134 if (!midi_port_nodes.empty()) {
1135 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1136 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1137 midi_port_stuff->add_child_nocopy (**n);
1139 node->add_child_nocopy (*midi_port_stuff);
1142 XMLNode& cfgxml (config.get_variables ());
1144 /* exclude search-paths from template */
1145 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1146 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1147 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1149 node->add_child_nocopy (cfgxml);
1151 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1153 child = node->add_child ("Sources");
1156 Glib::Threads::Mutex::Lock sl (source_lock);
1158 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1160 /* Don't save information about non-file Sources, or
1161 * about non-destructive file sources that are empty
1162 * and unused by any regions.
1165 boost::shared_ptr<FileSource> fs;
1167 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1169 if (!fs->destructive()) {
1170 if (fs->empty() && !fs->used()) {
1175 child->add_child_nocopy (siter->second->get_state());
1180 child = node->add_child ("Regions");
1183 Glib::Threads::Mutex::Lock rl (region_lock);
1184 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1185 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1186 boost::shared_ptr<Region> r = i->second;
1187 /* only store regions not attached to playlists */
1188 if (r->playlist() == 0) {
1189 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1190 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1192 child->add_child_nocopy (r->get_state ());
1197 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1199 if (!cassocs.empty()) {
1200 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1202 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1204 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1205 i->first->id().print (buf, sizeof (buf));
1206 can->add_property (X_("copy"), buf);
1207 i->second->id().print (buf, sizeof (buf));
1208 can->add_property (X_("original"), buf);
1209 ca->add_child_nocopy (*can);
1219 node->add_child_nocopy (_locations->get_state());
1222 Locations loc (*this);
1223 // for a template, just create a new Locations, populate it
1224 // with the default start and end, and get the state for that.
1225 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1226 range->set (max_framepos, 0);
1228 XMLNode& locations_state = loc.get_state();
1230 if (ARDOUR::Profile->get_trx() && _locations) {
1231 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1232 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1233 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1234 locations_state.add_child_nocopy ((*i)->get_state ());
1238 node->add_child_nocopy (locations_state);
1241 child = node->add_child ("Bundles");
1243 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1244 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1245 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1247 child->add_child_nocopy (b->get_state());
1252 node->add_child_nocopy (_vca_manager->get_state());
1254 child = node->add_child ("Routes");
1256 boost::shared_ptr<RouteList> r = routes.reader ();
1258 RoutePublicOrderSorter cmp;
1259 RouteList public_order (*r);
1260 public_order.sort (cmp);
1262 /* the sort should have put the monitor out first */
1265 assert (_monitor_out == public_order.front());
1268 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1269 if (!(*i)->is_auditioner()) {
1271 child->add_child_nocopy ((*i)->get_state());
1273 child->add_child_nocopy ((*i)->get_template());
1279 playlists->add_state (node, full_state);
1281 child = node->add_child ("RouteGroups");
1282 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1283 child->add_child_nocopy ((*i)->get_state());
1287 XMLNode* gain_child = node->add_child ("Click");
1288 gain_child->add_child_nocopy (_click_io->state (full_state));
1289 gain_child->add_child_nocopy (_click_gain->state (full_state));
1293 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1294 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1298 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1299 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1302 node->add_child_nocopy (_speakers->get_state());
1303 node->add_child_nocopy (_tempo_map->get_state());
1304 node->add_child_nocopy (get_control_protocol_state());
1307 node->add_child_copy (*_extra_xml);
1311 Glib::Threads::Mutex::Lock lm (lua_lock);
1314 luabridge::LuaRef savedstate ((*_lua_save)());
1315 saved = savedstate.cast<std::string>();
1317 lua.collect_garbage ();
1320 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1321 std::string b64s (b64);
1324 XMLNode* script_node = new XMLNode (X_("Script"));
1325 script_node->add_property (X_("lua"), LUA_VERSION);
1326 script_node->add_content (b64s);
1327 node->add_child_nocopy (*script_node);
1334 Session::get_control_protocol_state ()
1336 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1337 return cpm.get_state();
1341 Session::set_state (const XMLNode& node, int version)
1346 XMLProperty const * prop;
1349 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1351 if (node.name() != X_("Session")) {
1352 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1356 if ((prop = node.property ("name")) != 0) {
1357 _name = prop->value ();
1360 if ((prop = node.property (X_("sample-rate"))) != 0) {
1362 _base_frame_rate = atoi (prop->value());
1363 _nominal_frame_rate = _base_frame_rate;
1365 assert (AudioEngine::instance()->running ());
1366 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1367 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1368 if (r.get_value_or (0)) {
1374 created_with = "unknown";
1375 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1376 if ((prop = child->property (X_("created-with"))) != 0) {
1377 created_with = prop->value ();
1381 setup_raid_path(_session_dir->root_path());
1383 if ((prop = node.property (X_("end-is-free"))) != 0) {
1384 _session_range_end_is_free = string_is_affirmative (prop->value());
1387 if ((prop = node.property (X_("id-counter"))) != 0) {
1389 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1390 ID::init_counter (x);
1392 /* old sessions used a timebased counter, so fake
1393 the startup ID counter based on a standard
1398 ID::init_counter (now);
1401 if ((prop = node.property (X_("name-counter"))) != 0) {
1402 init_name_id_counter (atoi (prop->value()));
1405 if ((prop = node.property (X_("event-counter"))) != 0) {
1406 Evoral::init_event_id_counter (atoi (prop->value()));
1409 if ((prop = node.property (X_("vca-counter"))) != 0) {
1411 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1412 VCA::set_next_vca_number (x);
1414 VCA::set_next_vca_number (1);
1417 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1418 _midi_ports->set_midi_port_states (child->children());
1421 IO::disable_connecting ();
1423 Stateful::save_extra_xml (node);
1425 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1426 load_options (*child);
1427 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1428 load_options (*child);
1430 error << _("Session: XML state has no options section") << endmsg;
1433 if (version >= 3000) {
1434 if ((child = find_named_node (node, "Metadata")) == 0) {
1435 warning << _("Session: XML state has no metadata section") << endmsg;
1436 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1441 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1442 _speakers->set_state (*child, version);
1445 if ((child = find_named_node (node, "Sources")) == 0) {
1446 error << _("Session: XML state has no sources section") << endmsg;
1448 } else if (load_sources (*child)) {
1452 if ((child = find_named_node (node, "TempoMap")) == 0) {
1453 error << _("Session: XML state has no Tempo Map section") << endmsg;
1455 } else if (_tempo_map->set_state (*child, version)) {
1459 if ((child = find_named_node (node, "Locations")) == 0) {
1460 error << _("Session: XML state has no locations section") << endmsg;
1462 } else if (_locations->set_state (*child, version)) {
1466 locations_changed ();
1468 if (_session_range_location) {
1469 AudioFileSource::set_header_position_offset (_session_range_location->start());
1472 if ((child = find_named_node (node, "Regions")) == 0) {
1473 error << _("Session: XML state has no Regions section") << endmsg;
1475 } else if (load_regions (*child)) {
1479 if ((child = find_named_node (node, "Playlists")) == 0) {
1480 error << _("Session: XML state has no playlists section") << endmsg;
1482 } else if (playlists->load (*this, *child)) {
1486 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1488 } else if (playlists->load_unused (*this, *child)) {
1492 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1493 if (load_compounds (*child)) {
1498 if (version >= 3000) {
1499 if ((child = find_named_node (node, "Bundles")) == 0) {
1500 warning << _("Session: XML state has no bundles section") << endmsg;
1503 /* We can't load Bundles yet as they need to be able
1504 to convert from port names to Port objects, which can't happen until
1506 _bundle_xml_node = new XMLNode (*child);
1510 if (version < 3000) {
1511 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1512 error << _("Session: XML state has no diskstreams section") << endmsg;
1514 } else if (load_diskstreams_2X (*child, version)) {
1519 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1520 _vca_manager->set_state (*child, version);
1523 if ((child = find_named_node (node, "Routes")) == 0) {
1524 error << _("Session: XML state has no routes section") << endmsg;
1526 } else if (load_routes (*child, version)) {
1530 /* Now that we have Routes and masters loaded, connect them if appropriate */
1532 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1534 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1535 _diskstreams_2X.clear ();
1537 if (version >= 3000) {
1539 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1540 error << _("Session: XML state has no route groups section") << endmsg;
1542 } else if (load_route_groups (*child, version)) {
1546 } else if (version < 3000) {
1548 if ((child = find_named_node (node, "EditGroups")) == 0) {
1549 error << _("Session: XML state has no edit groups section") << endmsg;
1551 } else if (load_route_groups (*child, version)) {
1555 if ((child = find_named_node (node, "MixGroups")) == 0) {
1556 error << _("Session: XML state has no mix groups section") << endmsg;
1558 } else if (load_route_groups (*child, version)) {
1563 if ((child = find_named_node (node, "Click")) == 0) {
1564 warning << _("Session: XML state has no click section") << endmsg;
1565 } else if (_click_io) {
1566 setup_click_state (&node);
1569 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1570 ControlProtocolManager::instance().set_state (*child, version);
1573 if ((child = find_named_node (node, "Script"))) {
1574 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1575 if (!(*n)->is_content ()) { continue; }
1577 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1579 Glib::Threads::Mutex::Lock lm (lua_lock);
1580 (*_lua_load)(std::string ((const char*)buf, size));
1581 } catch (luabridge::LuaException const& e) {
1582 cerr << "LuaException:" << e.what () << endl;
1588 update_route_record_state ();
1590 /* here beginneth the second phase ... */
1591 set_snapshot_name (_current_snapshot_name);
1593 StateReady (); /* EMIT SIGNAL */
1606 Session::load_routes (const XMLNode& node, int version)
1609 XMLNodeConstIterator niter;
1610 RouteList new_routes;
1612 nlist = node.children();
1616 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1618 boost::shared_ptr<Route> route;
1619 if (version < 3000) {
1620 route = XMLRouteFactory_2X (**niter, version);
1622 route = XMLRouteFactory (**niter, version);
1626 error << _("Session: cannot create Route from XML description.") << endmsg;
1630 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1632 new_routes.push_back (route);
1635 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1637 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1639 BootMessage (_("Finished adding tracks/busses"));
1644 boost::shared_ptr<Route>
1645 Session::XMLRouteFactory (const XMLNode& node, int version)
1647 boost::shared_ptr<Route> ret;
1649 if (node.name() != "Route") {
1653 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1655 DataType type = DataType::AUDIO;
1656 XMLProperty const * prop = node.property("default-type");
1659 type = DataType (prop->value());
1662 assert (type != DataType::NIL);
1666 boost::shared_ptr<Track> track;
1668 if (type == DataType::AUDIO) {
1669 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1671 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1674 if (track->init()) {
1678 if (track->set_state (node, version)) {
1682 BOOST_MARK_TRACK (track);
1686 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1687 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1689 if (r->init () == 0 && r->set_state (node, version) == 0) {
1690 BOOST_MARK_ROUTE (r);
1698 boost::shared_ptr<Route>
1699 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1701 boost::shared_ptr<Route> ret;
1703 if (node.name() != "Route") {
1707 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1709 ds_prop = node.property (X_("diskstream"));
1712 DataType type = DataType::AUDIO;
1713 XMLProperty const * prop = node.property("default-type");
1716 type = DataType (prop->value());
1719 assert (type != DataType::NIL);
1723 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1724 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1728 if (i == _diskstreams_2X.end()) {
1729 error << _("Could not find diskstream for route") << endmsg;
1730 return boost::shared_ptr<Route> ();
1733 boost::shared_ptr<Track> track;
1735 if (type == DataType::AUDIO) {
1736 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1738 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1741 if (track->init()) {
1745 if (track->set_state (node, version)) {
1749 track->set_diskstream (*i);
1751 BOOST_MARK_TRACK (track);
1755 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1756 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1758 if (r->init () == 0 && r->set_state (node, version) == 0) {
1759 BOOST_MARK_ROUTE (r);
1768 Session::load_regions (const XMLNode& node)
1771 XMLNodeConstIterator niter;
1772 boost::shared_ptr<Region> region;
1774 nlist = node.children();
1778 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1779 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1780 error << _("Session: cannot create Region from XML description.");
1781 XMLProperty const * name = (**niter).property("name");
1784 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1795 Session::load_compounds (const XMLNode& node)
1797 XMLNodeList calist = node.children();
1798 XMLNodeConstIterator caiter;
1799 XMLProperty const * caprop;
1801 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1802 XMLNode* ca = *caiter;
1806 if ((caprop = ca->property (X_("original"))) == 0) {
1809 orig_id = caprop->value();
1811 if ((caprop = ca->property (X_("copy"))) == 0) {
1814 copy_id = caprop->value();
1816 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1817 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1819 if (!orig || !copy) {
1820 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1826 RegionFactory::add_compound_association (orig, copy);
1833 Session::load_nested_sources (const XMLNode& node)
1836 XMLNodeConstIterator niter;
1838 nlist = node.children();
1840 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1841 if ((*niter)->name() == "Source") {
1843 /* it may already exist, so don't recreate it unnecessarily
1846 XMLProperty const * prop = (*niter)->property (X_("id"));
1848 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1852 ID source_id (prop->value());
1854 if (!source_by_id (source_id)) {
1857 SourceFactory::create (*this, **niter, true);
1859 catch (failed_constructor& err) {
1860 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1867 boost::shared_ptr<Region>
1868 Session::XMLRegionFactory (const XMLNode& node, bool full)
1870 XMLProperty const * type = node.property("type");
1874 const XMLNodeList& nlist = node.children();
1876 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1877 XMLNode *child = (*niter);
1878 if (child->name() == "NestedSource") {
1879 load_nested_sources (*child);
1883 if (!type || type->value() == "audio") {
1884 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1885 } else if (type->value() == "midi") {
1886 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1889 } catch (failed_constructor& err) {
1890 return boost::shared_ptr<Region> ();
1893 return boost::shared_ptr<Region> ();
1896 boost::shared_ptr<AudioRegion>
1897 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1899 XMLProperty const * prop;
1900 boost::shared_ptr<Source> source;
1901 boost::shared_ptr<AudioSource> as;
1903 SourceList master_sources;
1904 uint32_t nchans = 1;
1907 if (node.name() != X_("Region")) {
1908 return boost::shared_ptr<AudioRegion>();
1911 if ((prop = node.property (X_("channels"))) != 0) {
1912 nchans = atoi (prop->value().c_str());
1915 if ((prop = node.property ("name")) == 0) {
1916 cerr << "no name for this region\n";
1920 if ((prop = node.property (X_("source-0"))) == 0) {
1921 if ((prop = node.property ("source")) == 0) {
1922 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1923 return boost::shared_ptr<AudioRegion>();
1927 PBD::ID s_id (prop->value());
1929 if ((source = source_by_id (s_id)) == 0) {
1930 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1931 return boost::shared_ptr<AudioRegion>();
1934 as = boost::dynamic_pointer_cast<AudioSource>(source);
1936 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1937 return boost::shared_ptr<AudioRegion>();
1940 sources.push_back (as);
1942 /* pickup other channels */
1944 for (uint32_t n=1; n < nchans; ++n) {
1945 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1946 if ((prop = node.property (buf)) != 0) {
1948 PBD::ID id2 (prop->value());
1950 if ((source = source_by_id (id2)) == 0) {
1951 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1952 return boost::shared_ptr<AudioRegion>();
1955 as = boost::dynamic_pointer_cast<AudioSource>(source);
1957 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1958 return boost::shared_ptr<AudioRegion>();
1960 sources.push_back (as);
1964 for (uint32_t n = 0; n < nchans; ++n) {
1965 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1966 if ((prop = node.property (buf)) != 0) {
1968 PBD::ID id2 (prop->value());
1970 if ((source = source_by_id (id2)) == 0) {
1971 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1972 return boost::shared_ptr<AudioRegion>();
1975 as = boost::dynamic_pointer_cast<AudioSource>(source);
1977 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1978 return boost::shared_ptr<AudioRegion>();
1980 master_sources.push_back (as);
1985 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1987 /* a final detail: this is the one and only place that we know how long missing files are */
1989 if (region->whole_file()) {
1990 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1991 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1993 sfp->set_length (region->length());
1998 if (!master_sources.empty()) {
1999 if (master_sources.size() != nchans) {
2000 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2002 region->set_master_sources (master_sources);
2010 catch (failed_constructor& err) {
2011 return boost::shared_ptr<AudioRegion>();
2015 boost::shared_ptr<MidiRegion>
2016 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2018 XMLProperty const * prop;
2019 boost::shared_ptr<Source> source;
2020 boost::shared_ptr<MidiSource> ms;
2023 if (node.name() != X_("Region")) {
2024 return boost::shared_ptr<MidiRegion>();
2027 if ((prop = node.property ("name")) == 0) {
2028 cerr << "no name for this region\n";
2032 if ((prop = node.property (X_("source-0"))) == 0) {
2033 if ((prop = node.property ("source")) == 0) {
2034 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2035 return boost::shared_ptr<MidiRegion>();
2039 PBD::ID s_id (prop->value());
2041 if ((source = source_by_id (s_id)) == 0) {
2042 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2043 return boost::shared_ptr<MidiRegion>();
2046 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2048 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2049 return boost::shared_ptr<MidiRegion>();
2052 sources.push_back (ms);
2055 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2056 /* a final detail: this is the one and only place that we know how long missing files are */
2058 if (region->whole_file()) {
2059 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2060 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2062 sfp->set_length (region->length());
2070 catch (failed_constructor& err) {
2071 return boost::shared_ptr<MidiRegion>();
2076 Session::get_sources_as_xml ()
2079 XMLNode* node = new XMLNode (X_("Sources"));
2080 Glib::Threads::Mutex::Lock lm (source_lock);
2082 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2083 node->add_child_nocopy (i->second->get_state());
2090 Session::reset_write_sources (bool mark_write_complete, bool force)
2092 boost::shared_ptr<RouteList> rl = routes.reader();
2093 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2094 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2096 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2097 tr->reset_write_sources(mark_write_complete, force);
2098 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2104 Session::load_sources (const XMLNode& node)
2107 XMLNodeConstIterator niter;
2108 boost::shared_ptr<Source> source; /* don't need this but it stops some
2109 * versions of gcc complaining about
2110 * discarded return values.
2113 nlist = node.children();
2117 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2118 #ifdef PLATFORM_WINDOWS
2124 #ifdef PLATFORM_WINDOWS
2125 // do not show "insert media" popups (files embedded from removable media).
2126 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2128 if ((source = XMLSourceFactory (**niter)) == 0) {
2129 error << _("Session: cannot create Source from XML description.") << endmsg;
2131 #ifdef PLATFORM_WINDOWS
2132 SetErrorMode(old_mode);
2135 } catch (MissingSource& err) {
2136 #ifdef PLATFORM_WINDOWS
2137 SetErrorMode(old_mode);
2142 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2143 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2144 PROGRAM_NAME) << endmsg;
2148 if (!no_questions_about_missing_files) {
2149 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2154 switch (user_choice) {
2156 /* user added a new search location, so try again */
2161 /* user asked to quit the entire session load
2166 no_questions_about_missing_files = true;
2170 no_questions_about_missing_files = true;
2177 case DataType::AUDIO:
2178 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2181 case DataType::MIDI:
2182 /* The MIDI file is actually missing so
2183 * just create a new one in the same
2184 * location. Do not announce its
2188 if (!Glib::path_is_absolute (err.path)) {
2189 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2191 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2196 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2197 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2198 /* reset ID to match the missing one */
2199 source->set_id (**niter);
2200 /* Now we can announce it */
2201 SourceFactory::SourceCreated (source);
2212 boost::shared_ptr<Source>
2213 Session::XMLSourceFactory (const XMLNode& node)
2215 if (node.name() != "Source") {
2216 return boost::shared_ptr<Source>();
2220 /* note: do peak building in another thread when loading session state */
2221 return SourceFactory::create (*this, node, true);
2224 catch (failed_constructor& err) {
2225 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2226 return boost::shared_ptr<Source>();
2231 Session::save_template (string template_name, bool replace_existing)
2233 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2237 bool absolute_path = Glib::path_is_absolute (template_name);
2239 /* directory to put the template in */
2240 std::string template_dir_path;
2242 if (!absolute_path) {
2243 std::string user_template_dir(user_template_directory());
2245 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2246 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2247 user_template_dir, g_strerror (errno)) << endmsg;
2251 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2253 template_dir_path = template_name;
2256 if (!ARDOUR::Profile->get_trx()) {
2257 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2258 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2259 template_dir_path) << endmsg;
2263 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2264 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2265 template_dir_path, g_strerror (errno)) << endmsg;
2271 std::string template_file_path;
2273 if (ARDOUR::Profile->get_trx()) {
2274 template_file_path = template_name;
2276 if (absolute_path) {
2277 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2279 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2283 SessionSaveUnderway (); /* EMIT SIGNAL */
2288 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2289 tree.set_root (&get_template());
2292 if (!tree.write (template_file_path)) {
2293 error << _("template not saved") << endmsg;
2297 store_recent_templates (template_file_path);
2303 Session::refresh_disk_space ()
2305 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2307 Glib::Threads::Mutex::Lock lm (space_lock);
2309 /* get freespace on every FS that is part of the session path */
2311 _total_free_4k_blocks = 0;
2312 _total_free_4k_blocks_uncertain = false;
2314 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2315 #if defined(__NetBSD__)
2316 struct statvfs statfsbuf;
2318 statvfs (i->path.c_str(), &statfsbuf);
2320 struct statfs statfsbuf;
2322 statfs (i->path.c_str(), &statfsbuf);
2324 double const scale = statfsbuf.f_bsize / 4096.0;
2326 /* See if this filesystem is read-only */
2327 struct statvfs statvfsbuf;
2328 statvfs (i->path.c_str(), &statvfsbuf);
2330 /* f_bavail can be 0 if it is undefined for whatever
2331 filesystem we are looking at; Samba shares mounted
2332 via GVFS are an example of this.
2334 if (statfsbuf.f_bavail == 0) {
2335 /* block count unknown */
2337 i->blocks_unknown = true;
2338 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2339 /* read-only filesystem */
2341 i->blocks_unknown = false;
2343 /* read/write filesystem with known space */
2344 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2345 i->blocks_unknown = false;
2348 _total_free_4k_blocks += i->blocks;
2349 if (i->blocks_unknown) {
2350 _total_free_4k_blocks_uncertain = true;
2353 #elif defined PLATFORM_WINDOWS
2354 vector<string> scanned_volumes;
2355 vector<string>::iterator j;
2356 vector<space_and_path>::iterator i;
2357 DWORD nSectorsPerCluster, nBytesPerSector,
2358 nFreeClusters, nTotalClusters;
2362 _total_free_4k_blocks = 0;
2364 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2365 strncpy (disk_drive, (*i).path.c_str(), 3);
2369 volume_found = false;
2370 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2372 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2373 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2374 i->blocks = (uint32_t)(nFreeBytes / 4096);
2376 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2377 if (0 == j->compare(disk_drive)) {
2378 volume_found = true;
2383 if (!volume_found) {
2384 scanned_volumes.push_back(disk_drive);
2385 _total_free_4k_blocks += i->blocks;
2390 if (0 == _total_free_4k_blocks) {
2391 strncpy (disk_drive, path().c_str(), 3);
2394 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2396 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2397 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2398 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2405 Session::get_best_session_directory_for_new_audio ()
2407 vector<space_and_path>::iterator i;
2408 string result = _session_dir->root_path();
2410 /* handle common case without system calls */
2412 if (session_dirs.size() == 1) {
2416 /* OK, here's the algorithm we're following here:
2418 We want to select which directory to use for
2419 the next file source to be created. Ideally,
2420 we'd like to use a round-robin process so as to
2421 get maximum performance benefits from splitting
2422 the files across multiple disks.
2424 However, in situations without much diskspace, an
2425 RR approach may end up filling up a filesystem
2426 with new files while others still have space.
2427 Its therefore important to pay some attention to
2428 the freespace in the filesystem holding each
2429 directory as well. However, if we did that by
2430 itself, we'd keep creating new files in the file
2431 system with the most space until it was as full
2432 as all others, thus negating any performance
2433 benefits of this RAID-1 like approach.
2435 So, we use a user-configurable space threshold. If
2436 there are at least 2 filesystems with more than this
2437 much space available, we use RR selection between them.
2438 If not, then we pick the filesystem with the most space.
2440 This gets a good balance between the two
2444 refresh_disk_space ();
2446 int free_enough = 0;
2448 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2449 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2454 if (free_enough >= 2) {
2455 /* use RR selection process, ensuring that the one
2459 i = last_rr_session_dir;
2462 if (++i == session_dirs.end()) {
2463 i = session_dirs.begin();
2466 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2467 SessionDirectory sdir(i->path);
2468 if (sdir.create ()) {
2470 last_rr_session_dir = i;
2475 } while (i != last_rr_session_dir);
2479 /* pick FS with the most freespace (and that
2480 seems to actually work ...)
2483 vector<space_and_path> sorted;
2484 space_and_path_ascending_cmp cmp;
2486 sorted = session_dirs;
2487 sort (sorted.begin(), sorted.end(), cmp);
2489 for (i = sorted.begin(); i != sorted.end(); ++i) {
2490 SessionDirectory sdir(i->path);
2491 if (sdir.create ()) {
2493 last_rr_session_dir = i;
2503 Session::automation_dir () const
2505 return Glib::build_filename (_path, automation_dir_name);
2509 Session::analysis_dir () const
2511 return Glib::build_filename (_path, analysis_dir_name);
2515 Session::plugins_dir () const
2517 return Glib::build_filename (_path, plugins_dir_name);
2521 Session::externals_dir () const
2523 return Glib::build_filename (_path, externals_dir_name);
2527 Session::load_bundles (XMLNode const & node)
2529 XMLNodeList nlist = node.children();
2530 XMLNodeConstIterator niter;
2534 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2535 if ((*niter)->name() == "InputBundle") {
2536 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2537 } else if ((*niter)->name() == "OutputBundle") {
2538 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2540 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2549 Session::load_route_groups (const XMLNode& node, int version)
2551 XMLNodeList nlist = node.children();
2552 XMLNodeConstIterator niter;
2556 if (version >= 3000) {
2558 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2559 if ((*niter)->name() == "RouteGroup") {
2560 RouteGroup* rg = new RouteGroup (*this, "");
2561 add_route_group (rg);
2562 rg->set_state (**niter, version);
2566 } else if (version < 3000) {
2568 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2569 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2570 RouteGroup* rg = new RouteGroup (*this, "");
2571 add_route_group (rg);
2572 rg->set_state (**niter, version);
2581 state_file_filter (const string &str, void* /*arg*/)
2583 return (str.length() > strlen(statefile_suffix) &&
2584 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2588 remove_end(string state)
2590 string statename(state);
2592 string::size_type start,end;
2593 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2594 statename = statename.substr (start+1);
2597 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2598 end = statename.length();
2601 return string(statename.substr (0, end));
2605 Session::possible_states (string path)
2607 vector<string> states;
2608 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2610 transform(states.begin(), states.end(), states.begin(), remove_end);
2612 sort (states.begin(), states.end());
2618 Session::possible_states () const
2620 return possible_states(_path);
2624 Session::new_route_group (const std::string& name)
2626 RouteGroup* rg = NULL;
2628 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2629 if ((*i)->name () == name) {
2636 rg = new RouteGroup (*this, name);
2637 add_route_group (rg);
2643 Session::add_route_group (RouteGroup* g)
2645 _route_groups.push_back (g);
2646 route_group_added (g); /* EMIT SIGNAL */
2648 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2649 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2650 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2656 Session::remove_route_group (RouteGroup& rg)
2658 list<RouteGroup*>::iterator i;
2660 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2661 _route_groups.erase (i);
2664 route_group_removed (); /* EMIT SIGNAL */
2668 /** Set a new order for our route groups, without adding or removing any.
2669 * @param groups Route group list in the new order.
2672 Session::reorder_route_groups (list<RouteGroup*> groups)
2674 _route_groups = groups;
2676 route_groups_reordered (); /* EMIT SIGNAL */
2682 Session::route_group_by_name (string name)
2684 list<RouteGroup *>::iterator i;
2686 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2687 if ((*i)->name() == name) {
2695 Session::all_route_group() const
2697 return *_all_route_group;
2701 Session::add_commands (vector<Command*> const & cmds)
2703 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2709 Session::add_command (Command* const cmd)
2711 assert (_current_trans);
2712 DEBUG_UNDO_HISTORY (
2713 string_compose ("Current Undo Transaction %1, adding command: %2",
2714 _current_trans->name (),
2716 _current_trans->add_command (cmd);
2719 PBD::StatefulDiffCommand*
2720 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2722 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2728 Session::begin_reversible_command (const string& name)
2730 begin_reversible_command (g_quark_from_string (name.c_str ()));
2733 /** Begin a reversible command using a GQuark to identify it.
2734 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2735 * but there must be as many begin...()s as there are commit...()s.
2738 Session::begin_reversible_command (GQuark q)
2740 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2741 to hold all the commands that are committed. This keeps the order of
2742 commands correct in the history.
2745 if (_current_trans == 0) {
2746 DEBUG_UNDO_HISTORY (string_compose (
2747 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2749 /* start a new transaction */
2750 assert (_current_trans_quarks.empty ());
2751 _current_trans = new UndoTransaction();
2752 _current_trans->set_name (g_quark_to_string (q));
2754 DEBUG_UNDO_HISTORY (
2755 string_compose ("Begin Reversible Command, current transaction: %1",
2756 _current_trans->name ()));
2759 _current_trans_quarks.push_front (q);
2763 Session::abort_reversible_command ()
2765 if (_current_trans != 0) {
2766 DEBUG_UNDO_HISTORY (
2767 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2768 _current_trans->clear();
2769 delete _current_trans;
2771 _current_trans_quarks.clear();
2776 Session::commit_reversible_command (Command *cmd)
2778 assert (_current_trans);
2779 assert (!_current_trans_quarks.empty ());
2784 DEBUG_UNDO_HISTORY (
2785 string_compose ("Current Undo Transaction %1, adding command: %2",
2786 _current_trans->name (),
2788 _current_trans->add_command (cmd);
2791 DEBUG_UNDO_HISTORY (
2792 string_compose ("Commit Reversible Command, current transaction: %1",
2793 _current_trans->name ()));
2795 _current_trans_quarks.pop_front ();
2797 if (!_current_trans_quarks.empty ()) {
2798 DEBUG_UNDO_HISTORY (
2799 string_compose ("Commit Reversible Command, transaction is not "
2800 "top-level, current transaction: %1",
2801 _current_trans->name ()));
2802 /* the transaction we're committing is not the top-level one */
2806 if (_current_trans->empty()) {
2807 /* no commands were added to the transaction, so just get rid of it */
2808 DEBUG_UNDO_HISTORY (
2809 string_compose ("Commit Reversible Command, No commands were "
2810 "added to current transaction: %1",
2811 _current_trans->name ()));
2812 delete _current_trans;
2817 gettimeofday (&now, 0);
2818 _current_trans->set_timestamp (now);
2820 _history.add (_current_trans);
2825 accept_all_audio_files (const string& path, void* /*arg*/)
2827 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2831 if (!AudioFileSource::safe_audio_file_extension (path)) {
2839 accept_all_midi_files (const string& path, void* /*arg*/)
2841 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2845 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2846 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2847 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2851 accept_all_state_files (const string& path, void* /*arg*/)
2853 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2857 std::string const statefile_ext (statefile_suffix);
2858 if (path.length() >= statefile_ext.length()) {
2859 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2866 Session::find_all_sources (string path, set<string>& result)
2871 if (!tree.read (path)) {
2875 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2880 XMLNodeConstIterator niter;
2882 nlist = node->children();
2886 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2888 XMLProperty const * prop;
2890 if ((prop = (*niter)->property (X_("type"))) == 0) {
2894 DataType type (prop->value());
2896 if ((prop = (*niter)->property (X_("name"))) == 0) {
2900 if (Glib::path_is_absolute (prop->value())) {
2901 /* external file, ignore */
2909 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2910 result.insert (found_path);
2918 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2920 vector<string> state_files;
2922 string this_snapshot_path;
2928 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2929 ripped = ripped.substr (0, ripped.length() - 1);
2932 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2934 if (state_files.empty()) {
2939 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2940 this_snapshot_path += statefile_suffix;
2942 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2944 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2946 if (exclude_this_snapshot && *i == this_snapshot_path) {
2947 cerr << "\texcluded\n";
2952 if (find_all_sources (*i, result) < 0) {
2960 struct RegionCounter {
2961 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2962 AudioSourceList::iterator iter;
2963 boost::shared_ptr<Region> region;
2966 RegionCounter() : count (0) {}
2970 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2972 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2973 return r.get_value_or (1);
2977 Session::cleanup_regions ()
2979 bool removed = false;
2980 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2982 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2984 uint32_t used = playlists->region_use_count (i->second);
2986 if (used == 0 && !i->second->automatic ()) {
2987 boost::weak_ptr<Region> w = i->second;
2990 RegionFactory::map_remove (w);
2997 // re-check to remove parent references of compound regions
2998 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2999 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3003 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3004 if (0 == playlists->region_use_count (i->second)) {
3005 boost::weak_ptr<Region> w = i->second;
3007 RegionFactory::map_remove (w);
3014 /* dump the history list */
3021 Session::can_cleanup_peakfiles () const
3023 if (deletion_in_progress()) {
3026 if (!_writable || (_state_of_the_state & CannotSave)) {
3027 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3030 if (record_status() == Recording) {
3031 error << _("Cannot cleanup peak-files while recording") << endmsg;
3038 Session::cleanup_peakfiles ()
3040 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3045 assert (can_cleanup_peakfiles ());
3046 assert (!peaks_cleanup_in_progres());
3048 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3050 int timeout = 5000; // 5 seconds
3051 while (!SourceFactory::files_with_peaks.empty()) {
3052 Glib::usleep (1000);
3053 if (--timeout < 0) {
3054 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3055 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3060 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3061 boost::shared_ptr<AudioSource> as;
3062 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3063 as->close_peakfile();
3067 PBD::clear_directory (session_directory().peak_path());
3069 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3071 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3072 boost::shared_ptr<AudioSource> as;
3073 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3074 SourceFactory::setup_peakfile(as, true);
3081 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3083 pl->deep_sources (*all_sources);
3087 Session::cleanup_sources (CleanupReport& rep)
3089 // FIXME: needs adaptation to midi
3091 vector<boost::shared_ptr<Source> > dead_sources;
3094 vector<string> candidates;
3095 vector<string> unused;
3096 set<string> sources_used_by_all_snapshots;
3103 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3105 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3107 /* this is mostly for windows which doesn't allow file
3108 * renaming if the file is in use. But we don't special
3109 * case it because we need to know if this causes
3110 * problems, and the easiest way to notice that is to
3111 * keep it in place for all platforms.
3114 request_stop (false);
3116 _butler->wait_until_finished ();
3118 /* consider deleting all unused playlists */
3120 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3125 /* sync the "all regions" property of each playlist with its current state
3128 playlists->sync_all_regions_with_regions ();
3130 /* find all un-used sources */
3135 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3137 SourceMap::iterator tmp;
3142 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3146 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3147 dead_sources.push_back (i->second);
3148 i->second->drop_references ();
3154 /* build a list of all the possible audio directories for the session */
3156 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3157 SessionDirectory sdir ((*i).path);
3158 asp += sdir.sound_path();
3160 audio_path += asp.to_string();
3163 /* build a list of all the possible midi directories for the session */
3165 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3166 SessionDirectory sdir ((*i).path);
3167 msp += sdir.midi_path();
3169 midi_path += msp.to_string();
3171 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3172 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3174 /* add sources from all other snapshots as "used", but don't use this
3175 snapshot because the state file on disk still references sources we
3176 may have already dropped.
3179 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3181 /* Although the region factory has a list of all regions ever created
3182 * for this session, we're only interested in regions actually in
3183 * playlists right now. So merge all playlist regions lists together.
3185 * This will include the playlists used within compound regions.
3188 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3190 /* add our current source list
3193 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3194 boost::shared_ptr<FileSource> fs;
3195 SourceMap::iterator tmp = i;
3198 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3204 /* this is mostly for windows which doesn't allow file
3205 * renaming if the file is in use. But we do not special
3206 * case it because we need to know if this causes
3207 * problems, and the easiest way to notice that is to
3208 * keep it in place for all platforms.
3213 if (!fs->is_stub()) {
3215 /* Note that we're checking a list of all
3216 * sources across all snapshots with the list
3217 * of sources used by this snapshot.
3220 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3221 /* this source is in use by this snapshot */
3222 sources_used_by_all_snapshots.insert (fs->path());
3223 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3225 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3226 /* this source is NOT in use by this snapshot
3229 /* remove all related regions from RegionFactory master list
3232 RegionFactory::remove_regions_using_source (i->second);
3234 /* remove from our current source list
3235 * also. We may not remove it from
3236 * disk, because it may be used by
3237 * other snapshots, but it isn't used inside this
3238 * snapshot anymore, so we don't need a
3249 /* now check each candidate source to see if it exists in the list of
3250 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3253 cerr << "Candidates: " << candidates.size() << endl;
3254 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3256 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3261 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3263 tmppath1 = canonical_path (spath);
3264 tmppath2 = canonical_path ((*i));
3266 cerr << "\t => " << tmppath2 << endl;
3268 if (tmppath1 == tmppath2) {
3275 unused.push_back (spath);
3279 cerr << "Actually unused: " << unused.size() << endl;
3281 if (unused.empty()) {
3287 /* now try to move all unused files into the "dead" directory(ies) */
3289 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3294 /* don't move the file across filesystems, just
3295 stick it in the `dead_dir_name' directory
3296 on whichever filesystem it was already on.
3299 if ((*x).find ("/sounds/") != string::npos) {
3301 /* old school, go up 1 level */
3303 newpath = Glib::path_get_dirname (*x); // "sounds"
3304 newpath = Glib::path_get_dirname (newpath); // "session-name"
3308 /* new school, go up 4 levels */
3310 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3311 newpath = Glib::path_get_dirname (newpath); // "session-name"
3312 newpath = Glib::path_get_dirname (newpath); // "interchange"
3313 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3316 newpath = Glib::build_filename (newpath, dead_dir_name);
3318 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3319 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3323 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3325 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3327 /* the new path already exists, try versioning */
3329 char buf[PATH_MAX+1];
3333 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3336 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3337 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3341 if (version == 999) {
3342 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3346 newpath = newpath_v;
3351 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3352 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3353 newpath, g_strerror (errno)) << endmsg;
3357 /* see if there an easy to find peakfile for this file, and remove it.
3360 string base = Glib::path_get_basename (*x);
3361 base += "%A"; /* this is what we add for the channel suffix of all native files,
3362 or for the first channel of embedded files. it will miss
3363 some peakfiles for other channels
3365 string peakpath = construct_peak_filepath (base);
3367 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3368 if (::g_unlink (peakpath.c_str ()) != 0) {
3369 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3370 g_strerror (errno)) << endmsg;
3371 /* try to back out */
3372 ::g_rename (newpath.c_str (), _path.c_str ());
3377 rep.paths.push_back (*x);
3378 rep.space += statbuf.st_size;
3381 /* dump the history list */
3385 /* save state so we don't end up a session file
3386 referring to non-existent sources.
3393 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3399 Session::cleanup_trash_sources (CleanupReport& rep)
3401 // FIXME: needs adaptation for MIDI
3403 vector<space_and_path>::iterator i;
3409 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3411 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3413 clear_directory (dead_dir, &rep.space, &rep.paths);
3420 Session::set_dirty ()
3422 /* never mark session dirty during loading */
3424 if (_state_of_the_state & Loading) {
3428 bool was_dirty = dirty();
3430 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3434 DirtyChanged(); /* EMIT SIGNAL */
3440 Session::set_clean ()
3442 bool was_dirty = dirty();
3444 _state_of_the_state = Clean;
3448 DirtyChanged(); /* EMIT SIGNAL */
3453 Session::set_deletion_in_progress ()
3455 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3459 Session::clear_deletion_in_progress ()
3461 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3465 Session::add_controllable (boost::shared_ptr<Controllable> c)
3467 /* this adds a controllable to the list managed by the Session.
3468 this is a subset of those managed by the Controllable class
3469 itself, and represents the only ones whose state will be saved
3470 as part of the session.
3473 Glib::Threads::Mutex::Lock lm (controllables_lock);
3474 controllables.insert (c);
3477 struct null_deleter { void operator()(void const *) const {} };
3480 Session::remove_controllable (Controllable* c)
3482 if (_state_of_the_state & Deletion) {
3486 Glib::Threads::Mutex::Lock lm (controllables_lock);
3488 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3490 if (x != controllables.end()) {
3491 controllables.erase (x);
3495 boost::shared_ptr<Controllable>
3496 Session::controllable_by_id (const PBD::ID& id)
3498 Glib::Threads::Mutex::Lock lm (controllables_lock);
3500 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3501 if ((*i)->id() == id) {
3506 return boost::shared_ptr<Controllable>();
3509 boost::shared_ptr<Controllable>
3510 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3512 boost::shared_ptr<Controllable> c;
3513 boost::shared_ptr<Stripable> s;
3514 boost::shared_ptr<Route> r;
3516 switch (desc.top_level_type()) {
3517 case ControllableDescriptor::NamedRoute:
3519 std::string str = desc.top_level_name();
3521 if (str == "Master" || str == "master") {
3523 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3525 } else if (str == "auditioner") {
3528 s = route_by_name (desc.top_level_name());
3534 case ControllableDescriptor::PresentationOrderRoute:
3535 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3538 case ControllableDescriptor::PresentationOrderTrack:
3539 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3542 case ControllableDescriptor::PresentationOrderBus:
3543 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3546 case ControllableDescriptor::PresentationOrderVCA:
3547 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3550 case ControllableDescriptor::SelectionCount:
3551 s = route_by_selected_count (desc.selection_id());
3559 r = boost::dynamic_pointer_cast<Route> (s);
3561 switch (desc.subtype()) {
3562 case ControllableDescriptor::Gain:
3563 c = s->gain_control ();
3566 case ControllableDescriptor::Trim:
3567 c = s->trim_control ();
3570 case ControllableDescriptor::Solo:
3571 c = s->solo_control();
3574 case ControllableDescriptor::Mute:
3575 c = s->mute_control();
3578 case ControllableDescriptor::Recenable:
3579 c = s->rec_enable_control ();
3582 case ControllableDescriptor::PanDirection:
3583 c = s->pan_azimuth_control();
3586 case ControllableDescriptor::PanWidth:
3587 c = s->pan_width_control();
3590 case ControllableDescriptor::PanElevation:
3591 c = s->pan_elevation_control();
3594 case ControllableDescriptor::Balance:
3595 /* XXX simple pan control */
3598 case ControllableDescriptor::PluginParameter:
3600 uint32_t plugin = desc.target (0);
3601 uint32_t parameter_index = desc.target (1);
3603 /* revert to zero based counting */
3609 if (parameter_index > 0) {
3617 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3620 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3621 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3626 case ControllableDescriptor::SendGain: {
3627 uint32_t send = desc.target (0);
3634 c = r->send_level_controllable (send);
3639 /* relax and return a null pointer */
3647 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3650 Stateful::add_instant_xml (node, _path);
3653 if (write_to_config) {
3654 Config->add_instant_xml (node);
3659 Session::instant_xml (const string& node_name)
3661 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3662 if (get_disable_all_loaded_plugins ()) {
3666 return Stateful::instant_xml (node_name, _path);
3670 Session::save_history (string snapshot_name)
3678 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3679 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3683 if (snapshot_name.empty()) {
3684 snapshot_name = _current_snapshot_name;
3687 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3688 const string backup_filename = history_filename + backup_suffix;
3689 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3690 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3692 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3693 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3694 error << _("could not backup old history file, current history not saved") << endmsg;
3699 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3701 if (!tree.write (xml_path))
3703 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3705 if (g_remove (xml_path.c_str()) != 0) {
3706 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3707 xml_path, g_strerror (errno)) << endmsg;
3709 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3710 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3711 backup_path, g_strerror (errno)) << endmsg;
3721 Session::restore_history (string snapshot_name)
3725 if (snapshot_name.empty()) {
3726 snapshot_name = _current_snapshot_name;
3729 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3730 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3732 info << "Loading history from " << xml_path << endmsg;
3734 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3735 info << string_compose (_("%1: no history file \"%2\" for this session."),
3736 _name, xml_path) << endmsg;
3740 if (!tree.read (xml_path)) {
3741 error << string_compose (_("Could not understand session history file \"%1\""),
3742 xml_path) << endmsg;
3749 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3752 UndoTransaction* ut = new UndoTransaction ();
3755 ut->set_name(t->property("name")->value());
3756 stringstream ss(t->property("tv-sec")->value());
3758 ss.str(t->property("tv-usec")->value());
3760 ut->set_timestamp(tv);
3762 for (XMLNodeConstIterator child_it = t->children().begin();
3763 child_it != t->children().end(); child_it++)
3765 XMLNode *n = *child_it;
3768 if (n->name() == "MementoCommand" ||
3769 n->name() == "MementoUndoCommand" ||
3770 n->name() == "MementoRedoCommand") {
3772 if ((c = memento_command_factory(n))) {
3776 } else if (n->name() == "NoteDiffCommand") {
3777 PBD::ID id (n->property("midi-source")->value());
3778 boost::shared_ptr<MidiSource> midi_source =
3779 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3781 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3783 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3786 } else if (n->name() == "SysExDiffCommand") {
3788 PBD::ID id (n->property("midi-source")->value());
3789 boost::shared_ptr<MidiSource> midi_source =
3790 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3792 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3794 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3797 } else if (n->name() == "PatchChangeDiffCommand") {
3799 PBD::ID id (n->property("midi-source")->value());
3800 boost::shared_ptr<MidiSource> midi_source =
3801 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3803 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3805 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3808 } else if (n->name() == "StatefulDiffCommand") {
3809 if ((c = stateful_diff_command_factory (n))) {
3810 ut->add_command (c);
3813 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3824 Session::config_changed (std::string p, bool ours)
3830 if (p == "seamless-loop") {
3832 } else if (p == "rf-speed") {
3834 } else if (p == "auto-loop") {
3836 } else if (p == "auto-input") {
3838 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3839 /* auto-input only makes a difference if we're rolling */
3840 set_track_monitor_input_status (!config.get_auto_input());
3843 } else if (p == "punch-in") {
3847 if ((location = _locations->auto_punch_location()) != 0) {
3849 if (config.get_punch_in ()) {
3850 replace_event (SessionEvent::PunchIn, location->start());
3852 remove_event (location->start(), SessionEvent::PunchIn);
3856 } else if (p == "punch-out") {
3860 if ((location = _locations->auto_punch_location()) != 0) {
3862 if (config.get_punch_out()) {
3863 replace_event (SessionEvent::PunchOut, location->end());
3865 clear_events (SessionEvent::PunchOut);
3869 } else if (p == "edit-mode") {
3871 Glib::Threads::Mutex::Lock lm (playlists->lock);
3873 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3874 (*i)->set_edit_mode (Config->get_edit_mode ());
3877 } else if (p == "use-video-sync") {
3879 waiting_for_sync_offset = config.get_use_video_sync();
3881 } else if (p == "mmc-control") {
3883 //poke_midi_thread ();
3885 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3887 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3889 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3891 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3893 } else if (p == "midi-control") {
3895 //poke_midi_thread ();
3897 } else if (p == "raid-path") {
3899 setup_raid_path (config.get_raid_path());
3901 } else if (p == "timecode-format") {
3905 } else if (p == "video-pullup") {
3909 } else if (p == "seamless-loop") {
3911 if (play_loop && transport_rolling()) {
3912 // to reset diskstreams etc
3913 request_play_loop (true);
3916 } else if (p == "rf-speed") {
3918 cumulative_rf_motion = 0;
3921 } else if (p == "click-sound") {
3923 setup_click_sounds (1);
3925 } else if (p == "click-emphasis-sound") {
3927 setup_click_sounds (-1);
3929 } else if (p == "clicking") {
3931 if (Config->get_clicking()) {
3932 if (_click_io && click_data) { // don't require emphasis data
3939 } else if (p == "click-gain") {
3942 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3945 } else if (p == "send-mtc") {
3947 if (Config->get_send_mtc ()) {
3948 /* mark us ready to send */
3949 next_quarter_frame_to_send = 0;
3952 } else if (p == "send-mmc") {
3954 _mmc->enable_send (Config->get_send_mmc ());
3956 } else if (p == "jack-time-master") {
3958 engine().reset_timebase ();
3960 } else if (p == "native-file-header-format") {
3962 if (!first_file_header_format_reset) {
3963 reset_native_file_format ();
3966 first_file_header_format_reset = false;
3968 } else if (p == "native-file-data-format") {
3970 if (!first_file_data_format_reset) {
3971 reset_native_file_format ();
3974 first_file_data_format_reset = false;
3976 } else if (p == "external-sync") {
3977 if (!config.get_external_sync()) {
3978 drop_sync_source ();
3980 switch_to_sync_source (Config->get_sync_source());
3982 } else if (p == "denormal-model") {
3984 } else if (p == "history-depth") {
3985 set_history_depth (Config->get_history_depth());
3986 } else if (p == "remote-model") {
3987 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3990 } else if (p == "initial-program-change") {
3992 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3995 buf[0] = MIDI::program; // channel zero by default
3996 buf[1] = (Config->get_initial_program_change() & 0x7f);
3998 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4000 } else if (p == "solo-mute-override") {
4001 // catch_up_on_solo_mute_override ();
4002 } else if (p == "listen-position" || p == "pfl-position") {
4003 listen_position_changed ();
4004 } else if (p == "solo-control-is-listen-control") {
4005 solo_control_mode_changed ();
4006 } else if (p == "solo-mute-gain") {
4007 _solo_cut_control->Changed (true, Controllable::NoGroup);
4008 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4009 last_timecode_valid = false;
4010 } else if (p == "playback-buffer-seconds") {
4011 AudioSource::allocate_working_buffers (frame_rate());
4012 } else if (p == "ltc-source-port") {
4013 reconnect_ltc_input ();
4014 } else if (p == "ltc-sink-port") {
4015 reconnect_ltc_output ();
4016 } else if (p == "timecode-generator-offset") {
4017 ltc_tx_parse_offset();
4018 } else if (p == "auto-return-target-list") {
4019 follow_playhead_priority ();
4026 Session::set_history_depth (uint32_t d)
4028 _history.set_depth (d);
4032 Session::load_diskstreams_2X (XMLNode const & node, int)
4035 XMLNodeConstIterator citer;
4037 clist = node.children();
4039 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4042 /* diskstreams added automatically by DiskstreamCreated handler */
4043 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4044 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4045 _diskstreams_2X.push_back (dsp);
4047 error << _("Session: unknown diskstream type in XML") << endmsg;
4051 catch (failed_constructor& err) {
4052 error << _("Session: could not load diskstream via XML state") << endmsg;
4060 /** Connect things to the MMC object */
4062 Session::setup_midi_machine_control ()
4064 _mmc = new MIDI::MachineControl;
4066 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4067 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4069 if (!async_out || !async_out) {
4073 /* XXXX argh, passing raw pointers back into libmidi++ */
4075 MIDI::Port* mmc_in = async_in.get();
4076 MIDI::Port* mmc_out = async_out.get();
4078 _mmc->set_ports (mmc_in, mmc_out);
4080 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4081 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4082 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4083 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4084 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4085 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4086 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4087 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4088 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4089 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4090 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4091 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4092 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4094 /* also handle MIDI SPP because its so common */
4096 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4097 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4098 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4101 boost::shared_ptr<Controllable>
4102 Session::solo_cut_control() const
4104 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4105 controls in Ardour that currently get presented to the user in the GUI that require
4106 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4108 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4109 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4113 return _solo_cut_control;
4117 Session::save_snapshot_name (const std::string & n)
4119 /* assure Stateful::_instant_xml is loaded
4120 * add_instant_xml() only adds to existing data and defaults
4121 * to use an empty Tree otherwise
4123 instant_xml ("LastUsedSnapshot");
4125 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4126 last_used_snapshot->add_property ("name", string(n));
4127 add_instant_xml (*last_used_snapshot, false);
4131 Session::set_snapshot_name (const std::string & n)
4133 _current_snapshot_name = n;
4134 save_snapshot_name (n);
4138 Session::rename (const std::string& new_name)
4140 string legal_name = legalize_for_path (new_name);
4146 string const old_sources_root = _session_dir->sources_root();
4148 if (!_writable || (_state_of_the_state & CannotSave)) {
4149 error << _("Cannot rename read-only session.") << endmsg;
4150 return 0; // don't show "messed up" warning
4152 if (record_status() == Recording) {
4153 error << _("Cannot rename session while recording") << endmsg;
4154 return 0; // don't show "messed up" warning
4157 StateProtector stp (this);
4162 * interchange subdirectory
4166 * Backup files are left unchanged and not renamed.
4169 /* Windows requires that we close all files before attempting the
4170 * rename. This works on other platforms, but isn't necessary there.
4171 * Leave it in place for all platforms though, since it may help
4172 * catch issues that could arise if the way Source files work ever
4173 * change (since most developers are not using Windows).
4176 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4177 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4183 /* pass one: not 100% safe check that the new directory names don't
4187 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4191 /* this is a stupid hack because Glib::path_get_dirname() is
4192 * lexical-only, and so passing it /a/b/c/ gives a different
4193 * result than passing it /a/b/c ...
4196 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4197 oldstr = oldstr.substr (0, oldstr.length() - 1);
4200 string base = Glib::path_get_dirname (oldstr);
4202 newstr = Glib::build_filename (base, legal_name);
4204 cerr << "Looking for " << newstr << endl;
4206 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4207 cerr << " exists\n";
4216 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4222 /* this is a stupid hack because Glib::path_get_dirname() is
4223 * lexical-only, and so passing it /a/b/c/ gives a different
4224 * result than passing it /a/b/c ...
4227 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4228 oldstr = oldstr.substr (0, oldstr.length() - 1);
4231 string base = Glib::path_get_dirname (oldstr);
4232 newstr = Glib::build_filename (base, legal_name);
4234 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4236 cerr << "Rename " << oldstr << " => " << newstr << endl;
4237 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4238 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4239 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4243 /* Reset path in "session dirs" */
4248 /* reset primary SessionDirectory object */
4251 (*_session_dir) = newstr;
4256 /* now rename directory below session_dir/interchange */
4258 string old_interchange_dir;
4259 string new_interchange_dir;
4261 /* use newstr here because we renamed the path
4262 * (folder/directory) that used to be oldstr to newstr above
4265 v.push_back (newstr);
4266 v.push_back (interchange_dir_name);
4267 v.push_back (Glib::path_get_basename (oldstr));
4269 old_interchange_dir = Glib::build_filename (v);
4272 v.push_back (newstr);
4273 v.push_back (interchange_dir_name);
4274 v.push_back (legal_name);
4276 new_interchange_dir = Glib::build_filename (v);
4278 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4280 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4281 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4282 old_interchange_dir, new_interchange_dir,
4285 error << string_compose (_("renaming %s as %2 failed (%3)"),
4286 old_interchange_dir, new_interchange_dir,
4295 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4296 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4298 cerr << "Rename " << oldstr << " => " << newstr << endl;
4300 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4301 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4302 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4308 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4310 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4311 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4313 cerr << "Rename " << oldstr << " => " << newstr << endl;
4315 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4316 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4317 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4322 /* remove old name from recent sessions */
4323 remove_recent_sessions (_path);
4326 /* update file source paths */
4328 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4329 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4331 string p = fs->path ();
4332 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4334 SourceFactory::setup_peakfile(i->second, true);
4338 set_snapshot_name (new_name);
4343 /* save state again to get everything just right */
4345 save_state (_current_snapshot_name);
4347 /* add to recent sessions */
4349 store_recent_sessions (new_name, _path);
4355 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4357 bool found_sr = false;
4358 bool found_data_format = false;
4360 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4364 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4368 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4371 xmlFreeParserCtxt(ctxt);
4375 xmlNodePtr node = xmlDocGetRootElement(doc);
4378 xmlFreeParserCtxt(ctxt);
4385 for (attr = node->properties; attr; attr = attr->next) {
4386 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4387 sample_rate = atoi ((char*)attr->children->content);
4392 node = node->children;
4393 while (node != NULL) {
4394 if (strcmp((const char*) node->name, "Config")) {
4398 for (node = node->children; node; node = node->next) {
4399 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4400 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4402 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4404 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4406 found_data_format = true;
4416 xmlFreeParserCtxt(ctxt);
4418 return !(found_sr && found_data_format); // zero if they are both found
4422 Session::get_snapshot_from_instant (const std::string& session_dir)
4424 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4426 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4431 if (!tree.read (instant_xml_path)) {
4435 XMLProperty const * prop;
4436 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4437 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4438 return prop->value();
4444 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4445 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4448 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4452 SourcePathMap source_path_map;
4454 boost::shared_ptr<AudioFileSource> afs;
4459 Glib::Threads::Mutex::Lock lm (source_lock);
4461 cerr << " total sources = " << sources.size();
4463 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4464 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4470 if (fs->within_session()) {
4474 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4475 source_path_map[fs->path()].push_back (fs);
4477 SeveralFileSources v;
4479 source_path_map.insert (make_pair (fs->path(), v));
4485 cerr << " fsources = " << total << endl;
4487 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4489 /* tell caller where we are */
4491 string old_path = i->first;
4493 callback (n, total, old_path);
4495 cerr << old_path << endl;
4499 switch (i->second.front()->type()) {
4500 case DataType::AUDIO:
4501 new_path = new_audio_source_path_for_embedded (old_path);
4504 case DataType::MIDI:
4505 /* XXX not implemented yet */
4509 if (new_path.empty()) {
4513 cerr << "Move " << old_path << " => " << new_path << endl;
4515 if (!copy_file (old_path, new_path)) {
4516 cerr << "failed !\n";
4520 /* make sure we stop looking in the external
4521 dir/folder. Remember, this is an all-or-nothing
4522 operations, it doesn't merge just some files.
4524 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4526 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4527 (*f)->set_path (new_path);
4532 save_state ("", false, false);
4538 bool accept_all_files (string const &, void *)
4544 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4546 /* 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.
4551 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4553 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4555 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4557 v.push_back (new_session_folder); /* full path */
4558 v.push_back (interchange_dir_name);
4559 v.push_back (new_session_path); /* just one directory/folder */
4560 v.push_back (typedir);
4561 v.push_back (Glib::path_get_basename (old_path));
4563 return Glib::build_filename (v);
4567 Session::save_as (SaveAs& saveas)
4569 vector<string> files;
4570 string current_folder = Glib::path_get_dirname (_path);
4571 string new_folder = legalize_for_path (saveas.new_name);
4572 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4573 int64_t total_bytes = 0;
4577 int32_t internal_file_cnt = 0;
4579 vector<string> do_not_copy_extensions;
4580 do_not_copy_extensions.push_back (statefile_suffix);
4581 do_not_copy_extensions.push_back (pending_suffix);
4582 do_not_copy_extensions.push_back (backup_suffix);
4583 do_not_copy_extensions.push_back (temp_suffix);
4584 do_not_copy_extensions.push_back (history_suffix);
4586 /* get total size */
4588 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4590 /* need to clear this because
4591 * find_files_matching_filter() is cumulative
4596 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4598 all += files.size();
4600 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4602 g_stat ((*i).c_str(), &gsb);
4603 total_bytes += gsb.st_size;
4607 /* save old values so we can switch back if we are not switching to the new session */
4609 string old_path = _path;
4610 string old_name = _name;
4611 string old_snapshot = _current_snapshot_name;
4612 string old_sd = _session_dir->root_path();
4613 vector<string> old_search_path[DataType::num_types];
4614 string old_config_search_path[DataType::num_types];
4616 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4617 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4618 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4619 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4621 /* switch session directory */
4623 (*_session_dir) = to_dir;
4625 /* create new tree */
4627 if (!_session_dir->create()) {
4628 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4633 /* copy all relevant files. Find each location in session_dirs,
4634 * and copy files from there to target.
4637 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4639 /* need to clear this because
4640 * find_files_matching_filter() is cumulative
4645 const size_t prefix_len = (*sd).path.size();
4647 /* Work just on the files within this session dir */
4649 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4651 /* add dir separator to protect against collisions with
4652 * track names (e.g. track named "audiofiles" or
4656 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4657 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4658 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4660 /* copy all the files. Handling is different for media files
4661 than others because of the *silly* subtree we have below the interchange
4662 folder. That really was a bad idea, but I'm not fixing it as part of
4663 implementing ::save_as().
4666 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4668 std::string from = *i;
4671 string filename = Glib::path_get_basename (from);
4672 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4673 if (filename == ".DS_STORE") {
4678 if (from.find (audiofile_dir_string) != string::npos) {
4680 /* audio file: only copy if asked */
4682 if (saveas.include_media && saveas.copy_media) {
4684 string to = make_new_media_path (*i, to_dir, new_folder);
4686 info << "media file copying from " << from << " to " << to << endmsg;
4688 if (!copy_file (from, to)) {
4689 throw Glib::FileError (Glib::FileError::IO_ERROR,
4690 string_compose(_("\ncopying \"%1\" failed !"), from));
4694 /* we found media files inside the session folder */
4696 internal_file_cnt++;
4698 } else if (from.find (midifile_dir_string) != string::npos) {
4700 /* midi file: always copy unless
4701 * creating an empty new session
4704 if (saveas.include_media) {
4706 string to = make_new_media_path (*i, to_dir, new_folder);
4708 info << "media file copying from " << from << " to " << to << endmsg;
4710 if (!copy_file (from, to)) {
4711 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4715 /* we found media files inside the session folder */
4717 internal_file_cnt++;
4719 } else if (from.find (analysis_dir_string) != string::npos) {
4721 /* make sure analysis dir exists in
4722 * new session folder, but we're not
4723 * copying analysis files here, see
4727 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4732 /* normal non-media file. Don't copy state, history, etc.
4735 bool do_copy = true;
4737 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4738 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4739 /* end of filename matches extension, do not copy file */
4745 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4746 /* don't copy peakfiles if
4747 * we're not copying media
4753 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4755 info << "attempting to make directory/folder " << to << endmsg;
4757 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4758 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4761 info << "attempting to copy " << from << " to " << to << endmsg;
4763 if (!copy_file (from, to)) {
4764 throw Glib::FileError (Glib::FileError::IO_ERROR,
4765 string_compose(_("\ncopying \"%1\" failed !"), from));
4770 /* measure file size even if we're not going to copy so that our Progress
4771 signals are correct, since we included these do-not-copy files
4772 in the computation of the total size and file count.
4776 g_stat (from.c_str(), &gsb);
4777 copied += gsb.st_size;
4780 double fraction = (double) copied / total_bytes;
4782 bool keep_going = true;
4784 if (saveas.copy_media) {
4786 /* no need or expectation of this if
4787 * media is not being copied, because
4788 * it will be fast(ish).
4791 /* tell someone "X percent, file M of N"; M is one-based */
4793 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4801 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4807 /* copy optional folders, if any */
4809 string old = plugins_dir ();
4810 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4811 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4812 copy_files (old, newdir);
4815 old = externals_dir ();
4816 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4817 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4818 copy_files (old, newdir);
4821 old = automation_dir ();
4822 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4823 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4824 copy_files (old, newdir);
4827 if (saveas.include_media) {
4829 if (saveas.copy_media) {
4830 #ifndef PLATFORM_WINDOWS
4831 /* There are problems with analysis files on
4832 * Windows, because they used a colon in their
4833 * names as late as 4.0. Colons are not legal
4834 * under Windows even if NTFS allows them.
4836 * This is a tricky problem to solve so for
4837 * just don't copy these files. They will be
4838 * regenerated as-needed anyway, subject to the
4839 * existing issue that the filenames will be
4840 * rejected by Windows, which is a separate
4841 * problem (though related).
4844 /* only needed if we are copying media, since the
4845 * analysis data refers to media data
4848 old = analysis_dir ();
4849 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4850 string newdir = Glib::build_filename (to_dir, "analysis");
4851 copy_files (old, newdir);
4853 #endif /* PLATFORM_WINDOWS */
4859 set_snapshot_name (saveas.new_name);
4860 _name = saveas.new_name;
4862 if (saveas.include_media && !saveas.copy_media) {
4864 /* reset search paths of the new session (which we're pretending to be right now) to
4865 include the original session search path, so we can still find all audio.
4868 if (internal_file_cnt) {
4869 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4870 ensure_search_path_includes (*s, DataType::AUDIO);
4871 cerr << "be sure to include " << *s << " for audio" << endl;
4874 /* we do not do this for MIDI because we copy
4875 all MIDI files if saveas.include_media is
4881 bool was_dirty = dirty ();
4883 save_state ("", false, false, !saveas.include_media);
4884 save_default_options ();
4886 if (saveas.copy_media && saveas.copy_external) {
4887 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4888 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4892 saveas.final_session_folder_name = _path;
4894 store_recent_sessions (_name, _path);
4896 if (!saveas.switch_to) {
4898 /* switch back to the way things were */
4902 set_snapshot_name (old_snapshot);
4904 (*_session_dir) = old_sd;
4910 if (internal_file_cnt) {
4911 /* reset these to their original values */
4912 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4913 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4918 /* prune session dirs, and update disk space statistics
4923 session_dirs.clear ();
4924 session_dirs.push_back (sp);
4925 refresh_disk_space ();
4927 /* ensure that all existing tracks reset their current capture source paths
4929 reset_write_sources (true, true);
4931 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4932 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4935 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4936 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4942 if (fs->within_session()) {
4943 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4944 fs->set_path (newpath);
4949 } catch (Glib::FileError& e) {
4951 saveas.failure_message = e.what();
4953 /* recursively remove all the directories */
4955 remove_directory (to_dir);
4963 saveas.failure_message = _("unknown reason");
4965 /* recursively remove all the directories */
4967 remove_directory (to_dir);
4977 static void set_progress (Progress* p, size_t n, size_t t)
4979 p->set_progress (float (n) / float(t));
4983 Session::archive_session (const std::string& dest,
4984 const std::string& name,
4985 ArchiveEncode compress_audio,
4986 bool only_used_sources,
4989 if (dest.empty () || name.empty ()) {
4993 /* save current values */
4994 bool was_dirty = dirty ();
4995 string old_path = _path;
4996 string old_name = _name;
4997 string old_snapshot = _current_snapshot_name;
4998 string old_sd = _session_dir->root_path();
4999 string old_config_search_path[DataType::num_types];
5000 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5001 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5003 /* ensure that session-path is included in search-path */
5005 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5006 if ((*sd).path == old_path) {
5014 /* create temporary dir to save session to */
5015 #ifdef PLATFORM_WINDOWS
5016 char tmp[256] = "C:\\TEMP\\";
5017 GetTempPath (sizeof (tmp), tmp);
5019 char const* tmp = getenv("TMPDIR");
5024 if ((strlen (tmp) + 21) > 1024) {
5029 strcpy (tmptpl, tmp);
5030 strcat (tmptpl, "ardourarchive-XXXXXX");
5031 char* tmpdir = g_mkdtemp (tmptpl);
5037 std::string to_dir = std::string (tmpdir);
5039 /* switch session directory temporarily */
5040 (*_session_dir) = to_dir;
5042 if (!_session_dir->create()) {
5043 (*_session_dir) = old_sd;
5044 remove_directory (to_dir);
5048 /* prepare archive */
5049 string archive = Glib::build_filename (dest, name + ".tar.xz");
5051 PBD::ScopedConnectionList progress_connection;
5052 PBD::FileArchive ar (archive);
5054 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5057 /* collect files to archive */
5058 std::map<string,string> filemap;
5060 vector<string> do_not_copy_extensions;
5061 do_not_copy_extensions.push_back (statefile_suffix);
5062 do_not_copy_extensions.push_back (pending_suffix);
5063 do_not_copy_extensions.push_back (backup_suffix);
5064 do_not_copy_extensions.push_back (temp_suffix);
5065 do_not_copy_extensions.push_back (history_suffix);
5067 vector<string> blacklist_dirs;
5068 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5069 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5070 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5071 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5072 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5073 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5075 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5076 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5078 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5079 if (only_used_sources) {
5080 playlists->sync_all_regions_with_regions ();
5081 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5084 // collect audio sources for this session, calc total size for encoding
5085 // add option to only include *used* sources (see Session::cleanup_sources)
5086 size_t total_size = 0;
5088 Glib::Threads::Mutex::Lock lm (source_lock);
5089 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5090 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5091 if (!afs || afs->readable_length () == 0) {
5095 if (only_used_sources) {
5099 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5104 std::string from = afs->path();
5106 if (compress_audio != NO_ENCODE) {
5107 total_size += afs->readable_length ();
5109 if (afs->within_session()) {
5110 filemap[from] = make_new_media_path (from, name, name);
5112 filemap[from] = make_new_media_path (from, name, name);
5113 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5120 if (compress_audio != NO_ENCODE) {
5122 progress->set_progress (2); // set to "encoding"
5123 progress->set_progress (0);
5126 Glib::Threads::Mutex::Lock lm (source_lock);
5127 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5128 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5129 if (!afs || afs->readable_length () == 0) {
5133 if (only_used_sources) {
5137 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5142 orig_sources[afs] = afs->path();
5143 orig_gain[afs] = afs->gain();
5145 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5146 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5147 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5150 progress->descend ((float)afs->readable_length () / total_size);
5154 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5155 afs->replace_file (new_path);
5156 afs->set_gain (ns->gain(), true);
5159 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5163 progress->ascend ();
5169 progress->set_progress (-1); // set to "archiving"
5170 progress->set_progress (0);
5173 /* index files relevant for this session */
5174 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5175 vector<string> files;
5177 size_t prefix_len = (*sd).path.size();
5178 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5182 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5184 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5185 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5186 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5188 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5189 std::string from = *i;
5192 string filename = Glib::path_get_basename (from);
5193 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5194 if (filename == ".DS_STORE") {
5199 if (from.find (audiofile_dir_string) != string::npos) {
5201 } else if (from.find (midifile_dir_string) != string::npos) {
5202 filemap[from] = make_new_media_path (from, name, name);
5203 } else if (from.find (videofile_dir_string) != string::npos) {
5204 filemap[from] = make_new_media_path (from, name, name);
5206 bool do_copy = true;
5207 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5208 if (from.find (*v) != string::npos) {
5213 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5214 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5221 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5227 /* write session file */
5229 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5231 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5234 save_default_options ();
5236 size_t prefix_len = _path.size();
5237 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5241 /* collect session-state files */
5242 vector<string> files;
5243 do_not_copy_extensions.clear ();
5244 do_not_copy_extensions.push_back (history_suffix);
5246 blacklist_dirs.clear ();
5247 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5249 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5250 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5251 std::string from = *i;
5252 bool do_copy = true;
5253 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5254 if (from.find (*v) != string::npos) {
5259 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5260 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5266 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5270 /* restore original values */
5273 set_snapshot_name (old_snapshot);
5274 (*_session_dir) = old_sd;
5278 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5279 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5281 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5282 i->first->replace_file (i->second);
5284 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5285 i->first->set_gain (i->second, true);
5288 int rv = ar.create (filemap);
5289 remove_directory (to_dir);
5295 Session::undo (uint32_t n)
5297 if (actively_recording()) {
5305 Session::redo (uint32_t n)
5307 if (actively_recording()) {