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/types_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/types_convert.h"
130 #include "ardour/user_bundle.h"
131 #include "ardour/vca.h"
132 #include "ardour/vca_manager.h"
134 #include "control_protocol/control_protocol.h"
136 #include "LuaBridge/LuaBridge.h"
138 #include "pbd/i18n.h"
142 using namespace ARDOUR;
145 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
148 Session::pre_engine_init (string fullpath)
150 if (fullpath.empty()) {
152 throw failed_constructor();
155 /* discover canonical fullpath */
157 _path = canonical_path(fullpath);
160 if (Profile->get_trx() ) {
161 // Waves TracksLive has a usecase of session replacement with a new one.
162 // We should check session state file (<session_name>.ardour) existance
163 // to determine if the session is new or not
165 string full_session_name = Glib::build_filename( fullpath, _name );
166 full_session_name += statefile_suffix;
168 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
170 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
173 /* finish initialization that can't be done in a normal C++ constructor
177 timerclear (&last_mmc_step);
178 g_atomic_int_set (&processing_prohibited, 0);
179 g_atomic_int_set (&_record_status, Disabled);
180 g_atomic_int_set (&_playback_load, 100);
181 g_atomic_int_set (&_capture_load, 100);
183 _all_route_group->set_active (true, this);
184 interpolation.add_channel_to (0, 0);
186 if (config.get_use_video_sync()) {
187 waiting_for_sync_offset = true;
189 waiting_for_sync_offset = false;
192 last_rr_session_dir = session_dirs.begin();
194 set_history_depth (Config->get_history_depth());
196 /* default: assume simple stereo speaker configuration */
198 _speakers->setup_default_speakers (2);
200 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
201 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
202 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
203 add_controllable (_solo_cut_control);
205 /* These are all static "per-class" signals */
207 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
208 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
209 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
210 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
211 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
213 /* stop IO objects from doing stuff until we're ready for them */
215 Delivery::disable_panners ();
216 IO::disable_connecting ();
220 Session::post_engine_init ()
222 BootMessage (_("Set block size and sample rate"));
224 set_block_size (_engine.samples_per_cycle());
225 set_frame_rate (_engine.sample_rate());
227 BootMessage (_("Using configuration"));
229 _midi_ports = new MidiPortManager;
231 MIDISceneChanger* msc;
233 _scene_changer = msc = new MIDISceneChanger (*this);
234 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
235 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
237 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this, (bool*)(0)));
238 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
240 setup_midi_machine_control ();
242 if (_butler->start_thread()) {
243 error << _("Butler did not start") << endmsg;
247 if (start_midi_thread ()) {
248 error << _("MIDI I/O thread did not start") << endmsg;
252 setup_click_sounds (0);
253 setup_midi_control ();
255 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
256 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
259 /* tempo map requires sample rate knowledge */
262 _tempo_map = new TempoMap (_current_frame_rate);
263 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
264 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
266 /* MidiClock requires a tempo map */
269 midi_clock = new MidiClockTicker ();
270 midi_clock->set_session (this);
272 /* crossfades require sample rate knowledge */
274 SndFileSource::setup_standard_crossfades (*this, frame_rate());
275 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
276 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
278 AudioDiskstream::allocate_working_buffers();
279 refresh_disk_space ();
281 /* we're finally ready to call set_state() ... all objects have
282 * been created, the engine is running.
286 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
287 error << _("Could not set session state from XML") << endmsg;
291 // set_state() will call setup_raid_path(), but if it's a new session we need
292 // to call setup_raid_path() here.
293 setup_raid_path (_path);
298 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
299 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
301 Config->map_parameters (ff);
302 config.map_parameters (ft);
303 _butler->map_parameters ();
305 /* Reset all panners */
307 Delivery::reset_panners ();
309 /* this will cause the CPM to instantiate any protocols that are in use
310 * (or mandatory), which will pass it this Session, and then call
311 * set_state() on each instantiated protocol to match stored state.
314 ControlProtocolManager::instance().set_session (this);
316 /* This must be done after the ControlProtocolManager set_session above,
317 as it will set states for ports which the ControlProtocolManager creates.
320 // XXX set state of MIDI::Port's
321 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
323 /* And this must be done after the MIDI::Manager::set_port_states as
324 * it will try to make connections whose details are loaded by set_port_states.
329 /* Let control protocols know that we are now all connected, so they
330 * could start talking to surfaces if they want to.
333 ControlProtocolManager::instance().midi_connectivity_established ();
335 if (_is_new && !no_auto_connect()) {
336 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
337 auto_connect_master_bus ();
340 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
342 /* update latencies */
344 initialize_latencies ();
346 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
347 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
348 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
350 } catch (AudioEngine::PortRegistrationFailure& err) {
351 /* handle this one in a different way than all others, so that its clear what happened */
352 error << err.what() << endmsg;
354 } catch (std::exception const & e) {
355 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
358 error << _("Unknown exception during session setup") << endmsg;
362 BootMessage (_("Reset Remote Controls"));
364 // send_full_time_code (0);
365 _engine.transport_locate (0);
367 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
368 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
370 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
373 /* initial program change will be delivered later; see ::config_changed() */
375 _state_of_the_state = Clean;
377 Port::set_connecting_blocked (false);
379 DirtyChanged (); /* EMIT SIGNAL */
383 } else if (state_was_pending) {
385 remove_pending_capture_state ();
386 state_was_pending = false;
389 /* Now, finally, we can fill the playback buffers */
391 BootMessage (_("Filling playback buffers"));
393 boost::shared_ptr<RouteList> rl = routes.reader();
394 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
395 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
396 if (trk && !trk->hidden()) {
397 trk->seek (_transport_frame, true);
405 Session::session_loaded ()
409 _state_of_the_state = Clean;
411 DirtyChanged (); /* EMIT SIGNAL */
415 } else if (state_was_pending) {
417 remove_pending_capture_state ();
418 state_was_pending = false;
421 /* Now, finally, we can fill the playback buffers */
423 BootMessage (_("Filling playback buffers"));
424 force_locate (_transport_frame, false);
428 Session::raid_path () const
430 Searchpath raid_search_path;
432 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
433 raid_search_path += (*i).path;
436 return raid_search_path.to_string ();
440 Session::setup_raid_path (string path)
449 session_dirs.clear ();
451 Searchpath search_path(path);
452 Searchpath sound_search_path;
453 Searchpath midi_search_path;
455 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
457 sp.blocks = 0; // not needed
458 session_dirs.push_back (sp);
460 SessionDirectory sdir(sp.path);
462 sound_search_path += sdir.sound_path ();
463 midi_search_path += sdir.midi_path ();
466 // reset the round-robin soundfile path thingie
467 last_rr_session_dir = session_dirs.begin();
471 Session::path_is_within_session (const std::string& path)
473 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
474 if (PBD::path_is_within (i->path, path)) {
482 Session::ensure_subdirs ()
486 dir = session_directory().peak_path();
488 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
489 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
493 dir = session_directory().sound_path();
495 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
496 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
500 dir = session_directory().midi_path();
502 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
503 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
507 dir = session_directory().dead_path();
509 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
510 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
514 dir = session_directory().export_path();
516 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
517 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
521 dir = analysis_dir ();
523 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
524 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
528 dir = plugins_dir ();
530 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
531 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
535 dir = externals_dir ();
537 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
538 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
545 /** @param session_template directory containing session template, or empty.
546 * Caller must not hold process lock.
549 Session::create (const string& session_template, BusProfile* bus_profile)
551 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
552 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
556 if (ensure_subdirs ()) {
560 _writable = exists_and_writable (_path);
562 if (!session_template.empty()) {
563 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
565 FILE* in = g_fopen (in_path.c_str(), "rb");
568 /* no need to call legalize_for_path() since the string
569 * in session_template is already a legal path name
571 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
573 FILE* out = g_fopen (out_path.c_str(), "wb");
577 stringstream new_session;
580 size_t charsRead = fread (buf, sizeof(char), 1024, in);
583 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
588 if (charsRead == 0) {
591 new_session.write (buf, charsRead);
595 string file_contents = new_session.str();
596 size_t writeSize = file_contents.length();
597 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
598 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
606 if (!ARDOUR::Profile->get_trx()) {
607 /* Copy plugin state files from template to new session */
608 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
609 copy_recurse (template_plugins, plugins_dir ());
615 error << string_compose (_("Could not open %1 for writing session template"), out_path)
622 error << string_compose (_("Could not open session template %1 for reading"), in_path)
629 if (Profile->get_trx()) {
631 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
632 * Remember that this is a brand new session. Sessions
633 * loaded from saved state will get this range from the saved state.
636 set_session_range_location (0, 0);
638 /* Initial loop location, from absolute zero, length 10 seconds */
640 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
641 _locations->add (loc, true);
642 set_auto_loop_location (loc);
645 _state_of_the_state = Clean;
647 /* set up Master Out and Monitor Out if necessary */
652 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
654 // Waves Tracks: always create master bus for Tracks
655 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
656 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
664 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
665 r->input()->ensure_io (count, false, this);
666 r->output()->ensure_io (count, false, this);
672 /* prohibit auto-connect to master, because there isn't one */
673 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
677 add_routes (rl, false, false, false, PresentationInfo::max_order);
680 // Waves Tracks: Skip this. Always use autoconnection for Tracks
681 if (!ARDOUR::Profile->get_trx()) {
683 /* this allows the user to override settings with an environment variable.
686 if (no_auto_connect()) {
687 bus_profile->input_ac = AutoConnectOption (0);
688 bus_profile->output_ac = AutoConnectOption (0);
691 Config->set_input_auto_connect (bus_profile->input_ac);
692 Config->set_output_auto_connect (bus_profile->output_ac);
696 if (Config->get_use_monitor_bus() && bus_profile) {
697 add_monitor_section ();
704 Session::maybe_write_autosave()
706 if (dirty() && record_status() != Recording) {
707 save_state("", true);
712 Session::remove_pending_capture_state ()
714 std::string pending_state_file_path(_session_dir->root_path());
716 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
718 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
720 if (g_remove (pending_state_file_path.c_str()) != 0) {
721 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
722 pending_state_file_path, g_strerror (errno)) << endmsg;
726 /** Rename a state file.
727 * @param old_name Old snapshot name.
728 * @param new_name New snapshot name.
731 Session::rename_state (string old_name, string new_name)
733 if (old_name == _current_snapshot_name || old_name == _name) {
734 /* refuse to rename the current snapshot or the "main" one */
738 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
739 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
741 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
742 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
744 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
745 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
746 old_name, new_name, g_strerror(errno)) << endmsg;
750 /** Remove a state file.
751 * @param snapshot_name Snapshot name.
754 Session::remove_state (string snapshot_name)
756 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
757 // refuse to remove the current snapshot or the "main" one
761 std::string xml_path(_session_dir->root_path());
763 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
765 if (!create_backup_file (xml_path)) {
766 // don't remove it if a backup can't be made
767 // create_backup_file will log the error.
772 if (g_remove (xml_path.c_str()) != 0) {
773 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
774 xml_path, g_strerror (errno)) << endmsg;
778 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
780 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
782 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
785 std::string xml_path(_session_dir->root_path());
787 /* prevent concurrent saves from different threads */
789 Glib::Threads::Mutex::Lock lm (save_state_lock);
791 if (!_writable || (_state_of_the_state & CannotSave)) {
795 if (g_atomic_int_get(&_suspend_save)) {
799 _save_queued = false;
801 if (!_engine.connected ()) {
802 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"), PROGRAM_NAME)
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;
983 if (root.get_property ("version", version)) {
984 if (version.find ('.') != string::npos) {
985 /* old school version format */
986 if (version[0] == '2') {
987 Stateful::loading_state_version = 2000;
989 Stateful::loading_state_version = 3000;
992 Stateful::loading_state_version = string_to<int32_t>(version);
995 /* no version implies very old version of Ardour */
996 Stateful::loading_state_version = 1000;
999 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1001 std::string backup_path(_session_dir->root_path());
1002 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1003 backup_path = Glib::build_filename (backup_path, backup_filename);
1005 // only create a backup for a given statefile version once
1007 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1009 VersionMismatch (xmlpath, backup_path);
1011 if (!copy_file (xmlpath, backup_path)) {;
1017 save_snapshot_name (snapshot_name);
1023 Session::load_options (const XMLNode& node)
1026 config.set_variables (node);
1031 Session::save_default_options ()
1033 return config.save_state();
1037 Session::get_state()
1043 Session::get_template()
1045 /* if we don't disable rec-enable, diskstreams
1046 will believe they need to store their capture
1047 sources in their state node.
1050 disable_record (false);
1052 return state(false);
1055 typedef std::set<boost::shared_ptr<Playlist> > PlaylistSet;
1056 typedef std::set<boost::shared_ptr<Source> > SourceSet;
1059 Session::export_track_state (boost::shared_ptr<RouteList> rl, const string& path)
1061 if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1064 if (g_mkdir_with_parents (path.c_str(), 0755) != 0) {
1068 PBD::Unwinder<std::string> uw (_template_state_dir, path);
1071 XMLNode* node = new XMLNode("TrackState"); // XXX
1074 PlaylistSet playlists; // SessionPlaylists
1077 // these will work with new_route_from_template()
1078 // TODO: LV2 plugin-state-dir needs to be relative (on load?)
1079 child = node->add_child ("Routes");
1080 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1081 if ((*i)->is_auditioner()) {
1084 if ((*i)->is_master() || (*i)->is_monitor()) {
1087 child->add_child_nocopy ((*i)->get_state());
1088 boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track> (*i);
1090 playlists.insert (track->playlist ());
1094 // on load, Regions in the playlists need to resolve and map Source-IDs
1095 // also playlist needs to be merged or created with new-name..
1096 // ... and Diskstream in tracks adjusted to use the correct playlist
1097 child = node->add_child ("Playlists"); // SessionPlaylists::add_state
1098 for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1099 child->add_child_nocopy ((*i)->get_state ());
1100 boost::shared_ptr<RegionList> prl = (*i)->region_list ();
1101 for (RegionList::const_iterator s = prl->begin(); s != prl->end(); ++s) {
1102 const Region::SourceList& sl = (*s)->sources ();
1103 for (Region::SourceList::const_iterator sli = sl.begin(); sli != sl.end(); ++sli) {
1104 sources.insert (*sli);
1109 child = node->add_child ("Sources");
1110 for (SourceSet::const_iterator i = sources.begin(); i != sources.end(); ++i) {
1111 child->add_child_nocopy ((*i)->get_state ());
1112 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (*i);
1114 #ifdef PLATFORM_WINDOWS
1117 string p = fs->path ();
1118 PBD::copy_file (p, Glib::build_filename (path, Glib::path_get_basename (p)));
1122 std::string sn = Glib::build_filename (path, "share.axml");
1125 tree.set_root (node);
1126 return tree.write (sn.c_str());
1131 struct route_id_compare {
1133 operator() (const boost::shared_ptr<Route>& r1, const boost::shared_ptr<Route>& r2)
1135 return r1->id () < r2->id ();
1141 Session::state (bool full_state)
1144 XMLNode* node = new XMLNode("Session");
1147 node->set_property("version", CURRENT_SESSION_FILE_VERSION);
1149 child = node->add_child ("ProgramVersion");
1150 child->set_property("created-with", created_with);
1152 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1153 child->set_property("modified-with", modified_with);
1155 /* store configuration settings */
1159 node->set_property ("name", _name);
1160 node->set_property ("sample-rate", _base_frame_rate);
1162 if (session_dirs.size() > 1) {
1166 vector<space_and_path>::iterator i = session_dirs.begin();
1167 vector<space_and_path>::iterator next;
1169 ++i; /* skip the first one */
1173 while (i != session_dirs.end()) {
1177 if (next != session_dirs.end()) {
1178 p += G_SEARCHPATH_SEPARATOR;
1187 child = node->add_child ("Path");
1188 child->add_content (p);
1190 node->set_property ("end-is-free", _session_range_end_is_free);
1193 node->set_property ("end-is-free", _session_range_end_is_free);
1195 /* save the ID counter */
1197 node->set_property ("id-counter", ID::counter());
1199 node->set_property ("name-counter", name_id_counter ());
1201 /* save the event ID counter */
1203 node->set_property ("event-counter", Evoral::event_id_counter());
1205 /* save the VCA counter */
1207 node->set_property ("vca-counter", VCA::get_next_vca_number());
1209 /* various options */
1211 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1212 if (!midi_port_nodes.empty()) {
1213 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1214 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1215 midi_port_stuff->add_child_nocopy (**n);
1217 node->add_child_nocopy (*midi_port_stuff);
1220 XMLNode& cfgxml (config.get_variables ());
1222 /* exclude search-paths from template */
1223 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1224 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1225 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1227 node->add_child_nocopy (cfgxml);
1229 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1231 child = node->add_child ("Sources");
1234 Glib::Threads::Mutex::Lock sl (source_lock);
1236 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1238 /* Don't save information about non-file Sources, or
1239 * about non-destructive file sources that are empty
1240 * and unused by any regions.
1243 boost::shared_ptr<FileSource> fs;
1245 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1247 if (!fs->destructive()) {
1248 if (fs->empty() && !fs->used()) {
1253 child->add_child_nocopy (siter->second->get_state());
1258 child = node->add_child ("Regions");
1261 Glib::Threads::Mutex::Lock rl (region_lock);
1262 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1263 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1264 boost::shared_ptr<Region> r = i->second;
1265 /* only store regions not attached to playlists */
1266 if (r->playlist() == 0) {
1267 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1268 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1270 child->add_child_nocopy (r->get_state ());
1275 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1277 if (!cassocs.empty()) {
1278 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1280 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1281 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1282 can->set_property (X_("copy"), i->first->id());
1283 can->set_property (X_("original"), i->second->id());
1284 ca->add_child_nocopy (*can);
1292 node->add_child_nocopy (_locations->get_state());
1295 Locations loc (*this);
1296 const bool was_dirty = dirty();
1297 // for a template, just create a new Locations, populate it
1298 // with the default start and end, and get the state for that.
1299 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1300 range->set (max_framepos, 0);
1302 XMLNode& locations_state = loc.get_state();
1304 if (ARDOUR::Profile->get_trx() && _locations) {
1305 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1306 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1307 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1308 locations_state.add_child_nocopy ((*i)->get_state ());
1312 node->add_child_nocopy (locations_state);
1314 /* adding a location above will have marked the session
1315 * dirty. This is an artifact, so fix it if the session wasn't
1320 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
1324 child = node->add_child ("Bundles");
1326 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1327 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1328 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1330 child->add_child_nocopy (b->get_state());
1335 node->add_child_nocopy (_vca_manager->get_state());
1337 child = node->add_child ("Routes");
1339 boost::shared_ptr<RouteList> r = routes.reader ();
1341 route_id_compare cmp;
1342 RouteList xml_node_order (*r);
1343 xml_node_order.sort (cmp);
1345 for (RouteList::const_iterator i = xml_node_order.begin(); i != xml_node_order.end(); ++i) {
1346 if (!(*i)->is_auditioner()) {
1348 child->add_child_nocopy ((*i)->get_state());
1350 child->add_child_nocopy ((*i)->get_template());
1356 playlists->add_state (node, full_state);
1358 child = node->add_child ("RouteGroups");
1359 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1360 child->add_child_nocopy ((*i)->get_state());
1364 XMLNode* gain_child = node->add_child ("Click");
1365 gain_child->add_child_nocopy (_click_io->state (full_state));
1366 gain_child->add_child_nocopy (_click_gain->state (full_state));
1370 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1371 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1375 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1376 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1379 node->add_child_nocopy (_speakers->get_state());
1380 node->add_child_nocopy (_tempo_map->get_state());
1381 node->add_child_nocopy (get_control_protocol_state());
1384 node->add_child_copy (*_extra_xml);
1388 Glib::Threads::Mutex::Lock lm (lua_lock);
1391 luabridge::LuaRef savedstate ((*_lua_save)());
1392 saved = savedstate.cast<std::string>();
1394 lua.collect_garbage ();
1397 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1398 std::string b64s (b64);
1401 XMLNode* script_node = new XMLNode (X_("Script"));
1402 script_node->set_property (X_("lua"), LUA_VERSION);
1403 script_node->add_content (b64s);
1404 node->add_child_nocopy (*script_node);
1411 Session::get_control_protocol_state ()
1413 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1414 return cpm.get_state();
1418 Session::set_state (const XMLNode& node, int version)
1425 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1427 if (node.name() != X_("Session")) {
1428 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1432 node.get_property ("name", _name);
1434 if (node.get_property (X_("sample-rate"), _base_frame_rate)) {
1436 _nominal_frame_rate = _base_frame_rate;
1438 assert (AudioEngine::instance()->running ());
1439 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1440 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1441 if (r.get_value_or (0)) {
1447 created_with = "unknown";
1448 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1449 child->get_property (X_("created-with"), created_with);
1452 setup_raid_path(_session_dir->root_path());
1454 node.get_property (X_("end-is-free"), _session_range_end_is_free);
1457 if (node.get_property (X_("id-counter"), counter)) {
1458 ID::init_counter (counter);
1460 /* old sessions used a timebased counter, so fake
1461 * the startup ID counter based on a standard
1466 ID::init_counter (now);
1469 if (node.get_property (X_("name-counter"), counter)) {
1470 init_name_id_counter (counter);
1473 if (node.get_property (X_("event-counter"), counter)) {
1474 Evoral::init_event_id_counter (counter);
1477 if (node.get_property (X_("vca-counter"), counter)) {
1478 VCA::set_next_vca_number (counter);
1480 VCA::set_next_vca_number (1);
1483 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1484 _midi_ports->set_midi_port_states (child->children());
1487 IO::disable_connecting ();
1489 Stateful::save_extra_xml (node);
1491 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1492 load_options (*child);
1493 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1494 load_options (*child);
1496 error << _("Session: XML state has no options section") << endmsg;
1499 if (version >= 3000) {
1500 if ((child = find_named_node (node, "Metadata")) == 0) {
1501 warning << _("Session: XML state has no metadata section") << endmsg;
1502 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1507 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1508 _speakers->set_state (*child, version);
1511 if ((child = find_named_node (node, "Sources")) == 0) {
1512 error << _("Session: XML state has no sources section") << endmsg;
1514 } else if (load_sources (*child)) {
1518 if ((child = find_named_node (node, "TempoMap")) == 0) {
1519 error << _("Session: XML state has no Tempo Map section") << endmsg;
1521 } else if (_tempo_map->set_state (*child, version)) {
1525 if ((child = find_named_node (node, "Locations")) == 0) {
1526 error << _("Session: XML state has no locations section") << endmsg;
1528 } else if (_locations->set_state (*child, version)) {
1532 locations_changed ();
1534 if (_session_range_location) {
1535 AudioFileSource::set_header_position_offset (_session_range_location->start());
1538 if ((child = find_named_node (node, "Regions")) == 0) {
1539 error << _("Session: XML state has no Regions section") << endmsg;
1541 } else if (load_regions (*child)) {
1545 if ((child = find_named_node (node, "Playlists")) == 0) {
1546 error << _("Session: XML state has no playlists section") << endmsg;
1548 } else if (playlists->load (*this, *child)) {
1552 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1554 } else if (playlists->load_unused (*this, *child)) {
1558 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1559 if (load_compounds (*child)) {
1564 if (version >= 3000) {
1565 if ((child = find_named_node (node, "Bundles")) == 0) {
1566 warning << _("Session: XML state has no bundles section") << endmsg;
1569 /* We can't load Bundles yet as they need to be able
1570 * to convert from port names to Port objects, which can't happen until
1572 _bundle_xml_node = new XMLNode (*child);
1576 if (version < 3000) {
1577 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1578 error << _("Session: XML state has no diskstreams section") << endmsg;
1580 } else if (load_diskstreams_2X (*child, version)) {
1585 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1586 _vca_manager->set_state (*child, version);
1589 if ((child = find_named_node (node, "Routes")) == 0) {
1590 error << _("Session: XML state has no routes section") << endmsg;
1592 } else if (load_routes (*child, version)) {
1596 /* Now that we have Routes and masters loaded, connect them if appropriate */
1598 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1600 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1601 _diskstreams_2X.clear ();
1603 if (version >= 3000) {
1605 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1606 error << _("Session: XML state has no route groups section") << endmsg;
1608 } else if (load_route_groups (*child, version)) {
1612 } else if (version < 3000) {
1614 if ((child = find_named_node (node, "EditGroups")) == 0) {
1615 error << _("Session: XML state has no edit groups section") << endmsg;
1617 } else if (load_route_groups (*child, version)) {
1621 if ((child = find_named_node (node, "MixGroups")) == 0) {
1622 error << _("Session: XML state has no mix groups section") << endmsg;
1624 } else if (load_route_groups (*child, version)) {
1629 if ((child = find_named_node (node, "Click")) == 0) {
1630 warning << _("Session: XML state has no click section") << endmsg;
1631 } else if (_click_io) {
1632 setup_click_state (&node);
1635 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1636 ControlProtocolManager::instance().set_state (*child, version);
1639 if ((child = find_named_node (node, "Script"))) {
1640 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1641 if (!(*n)->is_content ()) { continue; }
1643 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1645 Glib::Threads::Mutex::Lock lm (lua_lock);
1646 (*_lua_load)(std::string ((const char*)buf, size));
1647 } catch (luabridge::LuaException const& e) {
1648 cerr << "LuaException:" << e.what () << endl;
1654 update_route_record_state ();
1656 /* here beginneth the second phase ... */
1657 set_snapshot_name (_current_snapshot_name);
1659 StateReady (); /* EMIT SIGNAL */
1672 Session::load_routes (const XMLNode& node, int version)
1675 XMLNodeConstIterator niter;
1676 RouteList new_routes;
1678 nlist = node.children();
1682 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1684 boost::shared_ptr<Route> route;
1685 if (version < 3000) {
1686 route = XMLRouteFactory_2X (**niter, version);
1688 route = XMLRouteFactory (**niter, version);
1692 error << _("Session: cannot create Route from XML description.") << endmsg;
1696 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1698 new_routes.push_back (route);
1701 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1703 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1705 BootMessage (_("Finished adding tracks/busses"));
1710 boost::shared_ptr<Route>
1711 Session::XMLRouteFactory (const XMLNode& node, int version)
1713 boost::shared_ptr<Route> ret;
1715 if (node.name() != "Route") {
1719 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1721 DataType type = DataType::AUDIO;
1722 node.get_property("default-type", type);
1724 assert (type != DataType::NIL);
1728 boost::shared_ptr<Track> track;
1730 if (type == DataType::AUDIO) {
1731 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1733 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1736 if (track->init()) {
1740 if (track->set_state (node, version)) {
1744 BOOST_MARK_TRACK (track);
1748 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1749 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1751 if (r->init () == 0 && r->set_state (node, version) == 0) {
1752 BOOST_MARK_ROUTE (r);
1760 boost::shared_ptr<Route>
1761 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1763 boost::shared_ptr<Route> ret;
1765 if (node.name() != "Route") {
1769 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1771 ds_prop = node.property (X_("diskstream"));
1774 DataType type = DataType::AUDIO;
1775 node.get_property("default-type", type);
1777 assert (type != DataType::NIL);
1781 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1782 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1786 if (i == _diskstreams_2X.end()) {
1787 error << _("Could not find diskstream for route") << endmsg;
1788 return boost::shared_ptr<Route> ();
1791 boost::shared_ptr<Track> track;
1793 if (type == DataType::AUDIO) {
1794 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1796 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1799 if (track->init()) {
1803 if (track->set_state (node, version)) {
1807 track->set_diskstream (*i);
1809 BOOST_MARK_TRACK (track);
1813 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1814 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1816 if (r->init () == 0 && r->set_state (node, version) == 0) {
1817 BOOST_MARK_ROUTE (r);
1826 Session::load_regions (const XMLNode& node)
1829 XMLNodeConstIterator niter;
1830 boost::shared_ptr<Region> region;
1832 nlist = node.children();
1836 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1837 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1838 error << _("Session: cannot create Region from XML description.");
1839 XMLProperty const * name = (**niter).property("name");
1842 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1853 Session::load_compounds (const XMLNode& node)
1855 XMLNodeList calist = node.children();
1856 XMLNodeConstIterator caiter;
1857 XMLProperty const * caprop;
1859 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1860 XMLNode* ca = *caiter;
1864 if ((caprop = ca->property (X_("original"))) == 0) {
1867 orig_id = caprop->value();
1869 if ((caprop = ca->property (X_("copy"))) == 0) {
1872 copy_id = caprop->value();
1874 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1875 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1877 if (!orig || !copy) {
1878 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1884 RegionFactory::add_compound_association (orig, copy);
1891 Session::load_nested_sources (const XMLNode& node)
1894 XMLNodeConstIterator niter;
1896 nlist = node.children();
1898 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1899 if ((*niter)->name() == "Source") {
1901 /* it may already exist, so don't recreate it unnecessarily
1904 XMLProperty const * prop = (*niter)->property (X_("id"));
1906 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1910 ID source_id (prop->value());
1912 if (!source_by_id (source_id)) {
1915 SourceFactory::create (*this, **niter, true);
1917 catch (failed_constructor& err) {
1918 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1925 boost::shared_ptr<Region>
1926 Session::XMLRegionFactory (const XMLNode& node, bool full)
1928 XMLProperty const * type = node.property("type");
1932 const XMLNodeList& nlist = node.children();
1934 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1935 XMLNode *child = (*niter);
1936 if (child->name() == "NestedSource") {
1937 load_nested_sources (*child);
1941 if (!type || type->value() == "audio") {
1942 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1943 } else if (type->value() == "midi") {
1944 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1947 } catch (failed_constructor& err) {
1948 return boost::shared_ptr<Region> ();
1951 return boost::shared_ptr<Region> ();
1954 boost::shared_ptr<AudioRegion>
1955 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1957 XMLProperty const * prop;
1958 boost::shared_ptr<Source> source;
1959 boost::shared_ptr<AudioSource> as;
1961 SourceList master_sources;
1962 uint32_t nchans = 1;
1965 if (node.name() != X_("Region")) {
1966 return boost::shared_ptr<AudioRegion>();
1969 node.get_property (X_("channels"), nchans);
1971 if ((prop = node.property ("name")) == 0) {
1972 cerr << "no name for this region\n";
1976 if ((prop = node.property (X_("source-0"))) == 0) {
1977 if ((prop = node.property ("source")) == 0) {
1978 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1979 return boost::shared_ptr<AudioRegion>();
1983 PBD::ID s_id (prop->value());
1985 if ((source = source_by_id (s_id)) == 0) {
1986 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1987 return boost::shared_ptr<AudioRegion>();
1990 as = boost::dynamic_pointer_cast<AudioSource>(source);
1992 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1993 return boost::shared_ptr<AudioRegion>();
1996 sources.push_back (as);
1998 /* pickup other channels */
2000 for (uint32_t n=1; n < nchans; ++n) {
2001 snprintf (buf, sizeof(buf), X_("source-%d"), n);
2002 if ((prop = node.property (buf)) != 0) {
2004 PBD::ID id2 (prop->value());
2006 if ((source = source_by_id (id2)) == 0) {
2007 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2008 return boost::shared_ptr<AudioRegion>();
2011 as = boost::dynamic_pointer_cast<AudioSource>(source);
2013 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2014 return boost::shared_ptr<AudioRegion>();
2016 sources.push_back (as);
2020 for (uint32_t n = 0; n < nchans; ++n) {
2021 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
2022 if ((prop = node.property (buf)) != 0) {
2024 PBD::ID id2 (prop->value());
2026 if ((source = source_by_id (id2)) == 0) {
2027 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
2028 return boost::shared_ptr<AudioRegion>();
2031 as = boost::dynamic_pointer_cast<AudioSource>(source);
2033 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
2034 return boost::shared_ptr<AudioRegion>();
2036 master_sources.push_back (as);
2041 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
2043 /* a final detail: this is the one and only place that we know how long missing files are */
2045 if (region->whole_file()) {
2046 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2047 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2049 sfp->set_length (region->length());
2054 if (!master_sources.empty()) {
2055 if (master_sources.size() != nchans) {
2056 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2058 region->set_master_sources (master_sources);
2066 catch (failed_constructor& err) {
2067 return boost::shared_ptr<AudioRegion>();
2071 boost::shared_ptr<MidiRegion>
2072 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2074 XMLProperty const * prop;
2075 boost::shared_ptr<Source> source;
2076 boost::shared_ptr<MidiSource> ms;
2079 if (node.name() != X_("Region")) {
2080 return boost::shared_ptr<MidiRegion>();
2083 if ((prop = node.property ("name")) == 0) {
2084 cerr << "no name for this region\n";
2088 if ((prop = node.property (X_("source-0"))) == 0) {
2089 if ((prop = node.property ("source")) == 0) {
2090 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2091 return boost::shared_ptr<MidiRegion>();
2095 PBD::ID s_id (prop->value());
2097 if ((source = source_by_id (s_id)) == 0) {
2098 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2099 return boost::shared_ptr<MidiRegion>();
2102 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2104 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2105 return boost::shared_ptr<MidiRegion>();
2108 sources.push_back (ms);
2111 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2112 /* a final detail: this is the one and only place that we know how long missing files are */
2114 if (region->whole_file()) {
2115 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2116 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2118 sfp->set_length (region->length());
2126 catch (failed_constructor& err) {
2127 return boost::shared_ptr<MidiRegion>();
2132 Session::get_sources_as_xml ()
2135 XMLNode* node = new XMLNode (X_("Sources"));
2136 Glib::Threads::Mutex::Lock lm (source_lock);
2138 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2139 node->add_child_nocopy (i->second->get_state());
2146 Session::reset_write_sources (bool mark_write_complete, bool force)
2148 boost::shared_ptr<RouteList> rl = routes.reader();
2149 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2150 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2152 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2153 tr->reset_write_sources(mark_write_complete, force);
2154 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2160 Session::load_sources (const XMLNode& node)
2163 XMLNodeConstIterator niter;
2164 /* don't need this but it stops some
2165 * versions of gcc complaining about
2166 * discarded return values.
2168 boost::shared_ptr<Source> source;
2170 nlist = node.children();
2173 std::map<std::string, std::string> relocation;
2175 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2176 #ifdef PLATFORM_WINDOWS
2180 XMLNode srcnode (**niter);
2181 bool try_replace_abspath = true;
2185 #ifdef PLATFORM_WINDOWS
2186 // do not show "insert media" popups (files embedded from removable media).
2187 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2189 if ((source = XMLSourceFactory (srcnode)) == 0) {
2190 error << _("Session: cannot create Source from XML description.") << endmsg;
2192 #ifdef PLATFORM_WINDOWS
2193 SetErrorMode(old_mode);
2196 } catch (MissingSource& err) {
2197 #ifdef PLATFORM_WINDOWS
2198 SetErrorMode(old_mode);
2201 /* try previous abs path replacements first */
2202 if (try_replace_abspath && Glib::path_is_absolute (err.path)) {
2203 std::string dir = Glib::path_get_dirname (err.path);
2204 std::map<std::string, std::string>::const_iterator rl = relocation.find (dir);
2205 if (rl != relocation.end ()) {
2206 std::string newpath = Glib::build_filename (rl->second, Glib::path_get_basename (err.path));
2207 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2208 srcnode.set_property ("origin", newpath);
2209 try_replace_abspath = false;
2216 _missing_file_replacement = "";
2218 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2219 error << string_compose (_("An external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2220 PROGRAM_NAME) << endmsg;
2224 if (!no_questions_about_missing_files) {
2225 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2230 switch (user_choice) {
2232 /* user added a new search location
2233 * or selected a new absolute path,
2235 if (Glib::path_is_absolute (err.path)) {
2236 if (!_missing_file_replacement.empty ()) {
2237 /* replace origin, in XML */
2238 std::string newpath = Glib::build_filename (
2239 _missing_file_replacement, Glib::path_get_basename (err.path));
2240 srcnode.set_property ("origin", newpath);
2241 relocation[Glib::path_get_dirname (err.path)] = _missing_file_replacement;
2242 _missing_file_replacement = "";
2249 /* user asked to quit the entire session load */
2253 no_questions_about_missing_files = true;
2257 no_questions_about_missing_files = true;
2264 case DataType::AUDIO:
2265 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2268 case DataType::MIDI:
2269 /* The MIDI file is actually missing so
2270 * just create a new one in the same
2271 * location. Do not announce its
2275 if (!Glib::path_is_absolute (err.path)) {
2276 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2278 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2283 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2284 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2285 /* reset ID to match the missing one */
2286 source->set_id (**niter);
2287 /* Now we can announce it */
2288 SourceFactory::SourceCreated (source);
2299 boost::shared_ptr<Source>
2300 Session::XMLSourceFactory (const XMLNode& node)
2302 if (node.name() != "Source") {
2303 return boost::shared_ptr<Source>();
2307 /* note: do peak building in another thread when loading session state */
2308 return SourceFactory::create (*this, node, true);
2311 catch (failed_constructor& err) {
2312 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2313 return boost::shared_ptr<Source>();
2318 Session::save_template (string template_name, bool replace_existing)
2320 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2324 bool absolute_path = Glib::path_is_absolute (template_name);
2326 /* directory to put the template in */
2327 std::string template_dir_path;
2329 if (!absolute_path) {
2330 std::string user_template_dir(user_template_directory());
2332 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2333 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2334 user_template_dir, g_strerror (errno)) << endmsg;
2338 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2340 template_dir_path = template_name;
2343 if (!ARDOUR::Profile->get_trx()) {
2344 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2345 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2346 template_dir_path) << endmsg;
2350 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2351 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2352 template_dir_path, g_strerror (errno)) << endmsg;
2358 std::string template_file_path;
2360 if (ARDOUR::Profile->get_trx()) {
2361 template_file_path = template_name;
2363 if (absolute_path) {
2364 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2366 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2370 SessionSaveUnderway (); /* EMIT SIGNAL */
2375 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2376 tree.set_root (&get_template());
2379 if (!tree.write (template_file_path)) {
2380 error << _("template not saved") << endmsg;
2384 store_recent_templates (template_file_path);
2390 Session::refresh_disk_space ()
2392 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2394 Glib::Threads::Mutex::Lock lm (space_lock);
2396 /* get freespace on every FS that is part of the session path */
2398 _total_free_4k_blocks = 0;
2399 _total_free_4k_blocks_uncertain = false;
2401 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2402 #if defined(__NetBSD__)
2403 struct statvfs statfsbuf;
2405 statvfs (i->path.c_str(), &statfsbuf);
2407 struct statfs statfsbuf;
2409 statfs (i->path.c_str(), &statfsbuf);
2411 double const scale = statfsbuf.f_bsize / 4096.0;
2413 /* See if this filesystem is read-only */
2414 struct statvfs statvfsbuf;
2415 statvfs (i->path.c_str(), &statvfsbuf);
2417 /* f_bavail can be 0 if it is undefined for whatever
2418 filesystem we are looking at; Samba shares mounted
2419 via GVFS are an example of this.
2421 if (statfsbuf.f_bavail == 0) {
2422 /* block count unknown */
2424 i->blocks_unknown = true;
2425 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2426 /* read-only filesystem */
2428 i->blocks_unknown = false;
2430 /* read/write filesystem with known space */
2431 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2432 i->blocks_unknown = false;
2435 _total_free_4k_blocks += i->blocks;
2436 if (i->blocks_unknown) {
2437 _total_free_4k_blocks_uncertain = true;
2440 #elif defined PLATFORM_WINDOWS
2441 vector<string> scanned_volumes;
2442 vector<string>::iterator j;
2443 vector<space_and_path>::iterator i;
2444 DWORD nSectorsPerCluster, nBytesPerSector,
2445 nFreeClusters, nTotalClusters;
2449 _total_free_4k_blocks = 0;
2451 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2452 strncpy (disk_drive, (*i).path.c_str(), 3);
2456 volume_found = false;
2457 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2459 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2460 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2461 i->blocks = (uint32_t)(nFreeBytes / 4096);
2463 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2464 if (0 == j->compare(disk_drive)) {
2465 volume_found = true;
2470 if (!volume_found) {
2471 scanned_volumes.push_back(disk_drive);
2472 _total_free_4k_blocks += i->blocks;
2477 if (0 == _total_free_4k_blocks) {
2478 strncpy (disk_drive, path().c_str(), 3);
2481 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2483 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2484 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2485 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2492 Session::get_best_session_directory_for_new_audio ()
2494 vector<space_and_path>::iterator i;
2495 string result = _session_dir->root_path();
2497 /* handle common case without system calls */
2499 if (session_dirs.size() == 1) {
2503 /* OK, here's the algorithm we're following here:
2505 We want to select which directory to use for
2506 the next file source to be created. Ideally,
2507 we'd like to use a round-robin process so as to
2508 get maximum performance benefits from splitting
2509 the files across multiple disks.
2511 However, in situations without much diskspace, an
2512 RR approach may end up filling up a filesystem
2513 with new files while others still have space.
2514 Its therefore important to pay some attention to
2515 the freespace in the filesystem holding each
2516 directory as well. However, if we did that by
2517 itself, we'd keep creating new files in the file
2518 system with the most space until it was as full
2519 as all others, thus negating any performance
2520 benefits of this RAID-1 like approach.
2522 So, we use a user-configurable space threshold. If
2523 there are at least 2 filesystems with more than this
2524 much space available, we use RR selection between them.
2525 If not, then we pick the filesystem with the most space.
2527 This gets a good balance between the two
2531 refresh_disk_space ();
2533 int free_enough = 0;
2535 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2536 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2541 if (free_enough >= 2) {
2542 /* use RR selection process, ensuring that the one
2546 i = last_rr_session_dir;
2549 if (++i == session_dirs.end()) {
2550 i = session_dirs.begin();
2553 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2554 SessionDirectory sdir(i->path);
2555 if (sdir.create ()) {
2557 last_rr_session_dir = i;
2562 } while (i != last_rr_session_dir);
2566 /* pick FS with the most freespace (and that
2567 seems to actually work ...)
2570 vector<space_and_path> sorted;
2571 space_and_path_ascending_cmp cmp;
2573 sorted = session_dirs;
2574 sort (sorted.begin(), sorted.end(), cmp);
2576 for (i = sorted.begin(); i != sorted.end(); ++i) {
2577 SessionDirectory sdir(i->path);
2578 if (sdir.create ()) {
2580 last_rr_session_dir = i;
2590 Session::automation_dir () const
2592 return Glib::build_filename (_path, automation_dir_name);
2596 Session::analysis_dir () const
2598 return Glib::build_filename (_path, analysis_dir_name);
2602 Session::plugins_dir () const
2604 return Glib::build_filename (_path, plugins_dir_name);
2608 Session::externals_dir () const
2610 return Glib::build_filename (_path, externals_dir_name);
2614 Session::load_bundles (XMLNode const & node)
2616 XMLNodeList nlist = node.children();
2617 XMLNodeConstIterator niter;
2621 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2622 if ((*niter)->name() == "InputBundle") {
2623 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2624 } else if ((*niter)->name() == "OutputBundle") {
2625 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2627 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2636 Session::load_route_groups (const XMLNode& node, int version)
2638 XMLNodeList nlist = node.children();
2639 XMLNodeConstIterator niter;
2643 if (version >= 3000) {
2645 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2646 if ((*niter)->name() == "RouteGroup") {
2647 RouteGroup* rg = new RouteGroup (*this, "");
2648 add_route_group (rg);
2649 rg->set_state (**niter, version);
2653 } else if (version < 3000) {
2655 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2656 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2657 RouteGroup* rg = new RouteGroup (*this, "");
2658 add_route_group (rg);
2659 rg->set_state (**niter, version);
2668 state_file_filter (const string &str, void* /*arg*/)
2670 return (str.length() > strlen(statefile_suffix) &&
2671 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2675 remove_end(string state)
2677 string statename(state);
2679 string::size_type start,end;
2680 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2681 statename = statename.substr (start+1);
2684 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2685 end = statename.length();
2688 return string(statename.substr (0, end));
2692 Session::possible_states (string path)
2694 vector<string> states;
2695 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2697 transform(states.begin(), states.end(), states.begin(), remove_end);
2699 sort (states.begin(), states.end());
2705 Session::possible_states () const
2707 return possible_states(_path);
2711 Session::new_route_group (const std::string& name)
2713 RouteGroup* rg = NULL;
2715 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2716 if ((*i)->name () == name) {
2723 rg = new RouteGroup (*this, name);
2724 add_route_group (rg);
2730 Session::add_route_group (RouteGroup* g)
2732 _route_groups.push_back (g);
2733 route_group_added (g); /* EMIT SIGNAL */
2735 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2736 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2737 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2743 Session::remove_route_group (RouteGroup& rg)
2745 list<RouteGroup*>::iterator i;
2747 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2748 _route_groups.erase (i);
2751 route_group_removed (); /* EMIT SIGNAL */
2755 /** Set a new order for our route groups, without adding or removing any.
2756 * @param groups Route group list in the new order.
2759 Session::reorder_route_groups (list<RouteGroup*> groups)
2761 _route_groups = groups;
2763 route_groups_reordered (); /* EMIT SIGNAL */
2769 Session::route_group_by_name (string name)
2771 list<RouteGroup *>::iterator i;
2773 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2774 if ((*i)->name() == name) {
2782 Session::all_route_group() const
2784 return *_all_route_group;
2788 Session::add_commands (vector<Command*> const & cmds)
2790 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2796 Session::add_command (Command* const cmd)
2798 assert (_current_trans);
2799 DEBUG_UNDO_HISTORY (
2800 string_compose ("Current Undo Transaction %1, adding command: %2",
2801 _current_trans->name (),
2803 _current_trans->add_command (cmd);
2806 PBD::StatefulDiffCommand*
2807 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2809 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2815 Session::begin_reversible_command (const string& name)
2817 begin_reversible_command (g_quark_from_string (name.c_str ()));
2820 /** Begin a reversible command using a GQuark to identify it.
2821 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2822 * but there must be as many begin...()s as there are commit...()s.
2825 Session::begin_reversible_command (GQuark q)
2827 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2828 to hold all the commands that are committed. This keeps the order of
2829 commands correct in the history.
2832 if (_current_trans == 0) {
2833 DEBUG_UNDO_HISTORY (string_compose (
2834 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2836 /* start a new transaction */
2837 assert (_current_trans_quarks.empty ());
2838 _current_trans = new UndoTransaction();
2839 _current_trans->set_name (g_quark_to_string (q));
2841 DEBUG_UNDO_HISTORY (
2842 string_compose ("Begin Reversible Command, current transaction: %1",
2843 _current_trans->name ()));
2846 _current_trans_quarks.push_front (q);
2850 Session::abort_reversible_command ()
2852 if (_current_trans != 0) {
2853 DEBUG_UNDO_HISTORY (
2854 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2855 _current_trans->clear();
2856 delete _current_trans;
2858 _current_trans_quarks.clear();
2863 Session::commit_reversible_command (Command *cmd)
2865 assert (_current_trans);
2866 assert (!_current_trans_quarks.empty ());
2871 DEBUG_UNDO_HISTORY (
2872 string_compose ("Current Undo Transaction %1, adding command: %2",
2873 _current_trans->name (),
2875 _current_trans->add_command (cmd);
2878 DEBUG_UNDO_HISTORY (
2879 string_compose ("Commit Reversible Command, current transaction: %1",
2880 _current_trans->name ()));
2882 _current_trans_quarks.pop_front ();
2884 if (!_current_trans_quarks.empty ()) {
2885 DEBUG_UNDO_HISTORY (
2886 string_compose ("Commit Reversible Command, transaction is not "
2887 "top-level, current transaction: %1",
2888 _current_trans->name ()));
2889 /* the transaction we're committing is not the top-level one */
2893 if (_current_trans->empty()) {
2894 /* no commands were added to the transaction, so just get rid of it */
2895 DEBUG_UNDO_HISTORY (
2896 string_compose ("Commit Reversible Command, No commands were "
2897 "added to current transaction: %1",
2898 _current_trans->name ()));
2899 delete _current_trans;
2904 gettimeofday (&now, 0);
2905 _current_trans->set_timestamp (now);
2907 _history.add (_current_trans);
2912 accept_all_audio_files (const string& path, void* /*arg*/)
2914 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2918 if (!AudioFileSource::safe_audio_file_extension (path)) {
2926 accept_all_midi_files (const string& path, void* /*arg*/)
2928 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2932 return ( (path.length() > 4 && path.find (".mid") != (path.length() - 4))
2933 || (path.length() > 4 && path.find (".smf") != (path.length() - 4))
2934 || (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2938 accept_all_state_files (const string& path, void* /*arg*/)
2940 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2944 std::string const statefile_ext (statefile_suffix);
2945 if (path.length() >= statefile_ext.length()) {
2946 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2953 Session::find_all_sources (string path, set<string>& result)
2958 if (!tree.read (path)) {
2962 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2967 XMLNodeConstIterator niter;
2969 nlist = node->children();
2973 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2975 XMLProperty const * prop;
2977 if ((prop = (*niter)->property (X_("type"))) == 0) {
2981 DataType type (prop->value());
2983 if ((prop = (*niter)->property (X_("name"))) == 0) {
2987 if (Glib::path_is_absolute (prop->value())) {
2988 /* external file, ignore */
2996 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2997 result.insert (found_path);
3005 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
3007 vector<string> state_files;
3009 string this_snapshot_path;
3015 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
3016 ripped = ripped.substr (0, ripped.length() - 1);
3019 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
3021 if (state_files.empty()) {
3026 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
3027 this_snapshot_path += statefile_suffix;
3029 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
3031 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
3033 if (exclude_this_snapshot && *i == this_snapshot_path) {
3034 cerr << "\texcluded\n";
3039 if (find_all_sources (*i, result) < 0) {
3047 struct RegionCounter {
3048 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
3049 AudioSourceList::iterator iter;
3050 boost::shared_ptr<Region> region;
3053 RegionCounter() : count (0) {}
3057 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
3059 boost::optional<int> r = AskAboutPlaylistDeletion (p);
3060 return r.get_value_or (1);
3064 Session::cleanup_regions ()
3066 bool removed = false;
3067 const RegionFactory::RegionMap& regions (RegionFactory::regions());
3069 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3071 uint32_t used = playlists->region_use_count (i->second);
3073 if (used == 0 && !i->second->automatic ()) {
3074 boost::weak_ptr<Region> w = i->second;
3077 RegionFactory::map_remove (w);
3084 // re-check to remove parent references of compound regions
3085 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
3086 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3090 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3091 if (0 == playlists->region_use_count (i->second)) {
3092 boost::weak_ptr<Region> w = i->second;
3094 RegionFactory::map_remove (w);
3101 /* dump the history list */
3108 Session::can_cleanup_peakfiles () const
3110 if (deletion_in_progress()) {
3113 if (!_writable || (_state_of_the_state & CannotSave)) {
3114 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3117 if (record_status() == Recording) {
3118 error << _("Cannot cleanup peak-files while recording") << endmsg;
3125 Session::cleanup_peakfiles ()
3127 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3132 assert (can_cleanup_peakfiles ());
3133 assert (!peaks_cleanup_in_progres());
3135 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3137 int timeout = 5000; // 5 seconds
3138 while (!SourceFactory::files_with_peaks.empty()) {
3139 Glib::usleep (1000);
3140 if (--timeout < 0) {
3141 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3142 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3147 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3148 boost::shared_ptr<AudioSource> as;
3149 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3150 as->close_peakfile();
3154 PBD::clear_directory (session_directory().peak_path());
3156 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3158 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3159 boost::shared_ptr<AudioSource> as;
3160 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3161 SourceFactory::setup_peakfile(as, true);
3168 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3170 pl->deep_sources (*all_sources);
3174 Session::cleanup_sources (CleanupReport& rep)
3176 // FIXME: needs adaptation to midi
3178 vector<boost::shared_ptr<Source> > dead_sources;
3181 vector<string> candidates;
3182 vector<string> unused;
3183 set<string> sources_used_by_all_snapshots;
3190 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3192 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3194 /* this is mostly for windows which doesn't allow file
3195 * renaming if the file is in use. But we don't special
3196 * case it because we need to know if this causes
3197 * problems, and the easiest way to notice that is to
3198 * keep it in place for all platforms.
3201 request_stop (false);
3203 _butler->wait_until_finished ();
3205 /* consider deleting all unused playlists */
3207 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3212 /* sync the "all regions" property of each playlist with its current state */
3214 playlists->sync_all_regions_with_regions ();
3216 /* find all un-used sources */
3221 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3223 SourceMap::iterator tmp;
3228 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3232 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3233 dead_sources.push_back (i->second);
3234 i->second->drop_references ();
3240 /* build a list of all the possible audio directories for the session */
3242 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3243 SessionDirectory sdir ((*i).path);
3244 asp += sdir.sound_path();
3246 audio_path += asp.to_string();
3249 /* build a list of all the possible midi directories for the session */
3251 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3252 SessionDirectory sdir ((*i).path);
3253 msp += sdir.midi_path();
3255 midi_path += msp.to_string();
3257 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3258 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3260 /* add sources from all other snapshots as "used", but don't use this
3261 snapshot because the state file on disk still references sources we
3262 may have already dropped.
3265 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3267 /* Although the region factory has a list of all regions ever created
3268 * for this session, we're only interested in regions actually in
3269 * playlists right now. So merge all playlist regions lists together.
3271 * This will include the playlists used within compound regions.
3274 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3276 /* add our current source list
3279 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3280 boost::shared_ptr<FileSource> fs;
3281 SourceMap::iterator tmp = i;
3284 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3290 /* this is mostly for windows which doesn't allow file
3291 * renaming if the file is in use. But we do not special
3292 * case it because we need to know if this causes
3293 * problems, and the easiest way to notice that is to
3294 * keep it in place for all platforms.
3299 if (!fs->is_stub()) {
3301 /* Note that we're checking a list of all
3302 * sources across all snapshots with the list
3303 * of sources used by this snapshot.
3306 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3307 /* this source is in use by this snapshot */
3308 sources_used_by_all_snapshots.insert (fs->path());
3309 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3311 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3312 /* this source is NOT in use by this snapshot */
3314 /* remove all related regions from RegionFactory master list */
3316 RegionFactory::remove_regions_using_source (i->second);
3318 /* remove from our current source list
3319 * also. We may not remove it from
3320 * disk, because it may be used by
3321 * other snapshots, but it isn't used inside this
3322 * snapshot anymore, so we don't need a
3333 /* now check each candidate source to see if it exists in the list of
3334 * sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3337 cerr << "Candidates: " << candidates.size() << endl;
3338 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3340 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3345 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3347 tmppath1 = canonical_path (spath);
3348 tmppath2 = canonical_path ((*i));
3350 cerr << "\t => " << tmppath2 << endl;
3352 if (tmppath1 == tmppath2) {
3359 unused.push_back (spath);
3363 cerr << "Actually unused: " << unused.size() << endl;
3365 if (unused.empty()) {
3371 /* now try to move all unused files into the "dead" directory(ies) */
3373 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3378 /* don't move the file across filesystems, just
3379 * stick it in the `dead_dir_name' directory
3380 * on whichever filesystem it was already on.
3383 if ((*x).find ("/sounds/") != string::npos) {
3385 /* old school, go up 1 level */
3387 newpath = Glib::path_get_dirname (*x); // "sounds"
3388 newpath = Glib::path_get_dirname (newpath); // "session-name"
3392 /* new school, go up 4 levels */
3394 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3395 newpath = Glib::path_get_dirname (newpath); // "session-name"
3396 newpath = Glib::path_get_dirname (newpath); // "interchange"
3397 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3400 newpath = Glib::build_filename (newpath, dead_dir_name);
3402 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3403 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3407 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3409 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3411 /* the new path already exists, try versioning */
3413 char buf[PATH_MAX+1];
3417 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3420 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3421 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3425 if (version == 999) {
3426 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3430 newpath = newpath_v;
3435 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3436 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3437 newpath, g_strerror (errno)) << endmsg;
3441 /* see if there an easy to find peakfile for this file, and remove it. */
3443 string base = Glib::path_get_basename (*x);
3444 base += "%A"; /* this is what we add for the channel suffix of all native files,
3445 * or for the first channel of embedded files. it will miss
3446 * some peakfiles for other channels
3448 string peakpath = construct_peak_filepath (base);
3450 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3451 if (::g_unlink (peakpath.c_str ()) != 0) {
3452 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3453 g_strerror (errno)) << endmsg;
3454 /* try to back out */
3455 ::g_rename (newpath.c_str (), _path.c_str ());
3460 rep.paths.push_back (*x);
3461 rep.space += statbuf.st_size;
3464 /* dump the history list */
3468 /* save state so we don't end up a session file
3469 * referring to non-existent sources.
3476 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3482 Session::cleanup_trash_sources (CleanupReport& rep)
3484 // FIXME: needs adaptation for MIDI
3486 vector<space_and_path>::iterator i;
3492 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3494 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3496 clear_directory (dead_dir, &rep.space, &rep.paths);
3503 Session::set_dirty ()
3505 /* return early if there's nothing to do */
3510 /* never mark session dirty during loading */
3511 if (_state_of_the_state & Loading) {
3515 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3516 DirtyChanged(); /* EMIT SIGNAL */
3520 Session::set_clean ()
3522 bool was_dirty = dirty();
3524 _state_of_the_state = Clean;
3527 DirtyChanged(); /* EMIT SIGNAL */
3532 Session::set_deletion_in_progress ()
3534 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3538 Session::clear_deletion_in_progress ()
3540 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3544 Session::add_controllable (boost::shared_ptr<Controllable> c)
3546 /* this adds a controllable to the list managed by the Session.
3547 this is a subset of those managed by the Controllable class
3548 itself, and represents the only ones whose state will be saved
3549 as part of the session.
3552 Glib::Threads::Mutex::Lock lm (controllables_lock);
3553 controllables.insert (c);
3556 struct null_deleter { void operator()(void const *) const {} };
3559 Session::remove_controllable (Controllable* c)
3561 if (_state_of_the_state & Deletion) {
3565 Glib::Threads::Mutex::Lock lm (controllables_lock);
3567 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3569 if (x != controllables.end()) {
3570 controllables.erase (x);
3574 boost::shared_ptr<Controllable>
3575 Session::controllable_by_id (const PBD::ID& id)
3577 Glib::Threads::Mutex::Lock lm (controllables_lock);
3579 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3580 if ((*i)->id() == id) {
3585 return boost::shared_ptr<Controllable>();
3588 boost::shared_ptr<Controllable>
3589 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3591 boost::shared_ptr<Controllable> c;
3592 boost::shared_ptr<Stripable> s;
3593 boost::shared_ptr<Route> r;
3595 switch (desc.top_level_type()) {
3596 case ControllableDescriptor::NamedRoute:
3598 std::string str = desc.top_level_name();
3600 if (str == "Master" || str == "master") {
3602 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3604 } else if (str == "auditioner") {
3607 s = route_by_name (desc.top_level_name());
3613 case ControllableDescriptor::PresentationOrderRoute:
3614 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3617 case ControllableDescriptor::PresentationOrderTrack:
3618 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3621 case ControllableDescriptor::PresentationOrderBus:
3622 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3625 case ControllableDescriptor::PresentationOrderVCA:
3626 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3629 case ControllableDescriptor::SelectionCount:
3630 s = route_by_selected_count (desc.selection_id());
3638 r = boost::dynamic_pointer_cast<Route> (s);
3640 switch (desc.subtype()) {
3641 case ControllableDescriptor::Gain:
3642 c = s->gain_control ();
3645 case ControllableDescriptor::Trim:
3646 c = s->trim_control ();
3649 case ControllableDescriptor::Solo:
3650 c = s->solo_control();
3653 case ControllableDescriptor::Mute:
3654 c = s->mute_control();
3657 case ControllableDescriptor::Recenable:
3658 c = s->rec_enable_control ();
3661 case ControllableDescriptor::PanDirection:
3662 c = s->pan_azimuth_control();
3665 case ControllableDescriptor::PanWidth:
3666 c = s->pan_width_control();
3669 case ControllableDescriptor::PanElevation:
3670 c = s->pan_elevation_control();
3673 case ControllableDescriptor::Balance:
3674 /* XXX simple pan control */
3677 case ControllableDescriptor::PluginParameter:
3679 uint32_t plugin = desc.target (0);
3680 uint32_t parameter_index = desc.target (1);
3682 /* revert to zero based counting */
3688 if (parameter_index > 0) {
3696 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3699 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3700 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3705 case ControllableDescriptor::SendGain: {
3706 uint32_t send = desc.target (0);
3713 c = r->send_level_controllable (send);
3718 /* relax and return a null pointer */
3726 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3729 Stateful::add_instant_xml (node, _path);
3732 if (write_to_config) {
3733 Config->add_instant_xml (node);
3738 Session::instant_xml (const string& node_name)
3740 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3741 if (get_disable_all_loaded_plugins ()) {
3745 return Stateful::instant_xml (node_name, _path);
3749 Session::save_history (string snapshot_name)
3757 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3758 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3762 if (snapshot_name.empty()) {
3763 snapshot_name = _current_snapshot_name;
3766 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3767 const string backup_filename = history_filename + backup_suffix;
3768 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3769 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3771 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3772 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3773 error << _("could not backup old history file, current history not saved") << endmsg;
3778 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3780 if (!tree.write (xml_path))
3782 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3784 if (g_remove (xml_path.c_str()) != 0) {
3785 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3786 xml_path, g_strerror (errno)) << endmsg;
3788 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3789 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3790 backup_path, g_strerror (errno)) << endmsg;
3800 Session::restore_history (string snapshot_name)
3804 if (snapshot_name.empty()) {
3805 snapshot_name = _current_snapshot_name;
3808 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3809 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3811 info << "Loading history from " << xml_path << endmsg;
3813 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3814 info << string_compose (_("%1: no history file \"%2\" for this session."),
3815 _name, xml_path) << endmsg;
3819 if (!tree.read (xml_path)) {
3820 error << string_compose (_("Could not understand session history file \"%1\""),
3821 xml_path) << endmsg;
3828 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3831 UndoTransaction* ut = new UndoTransaction ();
3837 if (!t->get_property ("name", name) || !t->get_property ("tv-sec", tv_sec) ||
3838 !t->get_property ("tv-usec", tv_usec)) {
3842 ut->set_name (name);
3846 tv.tv_usec = tv_usec;
3847 ut->set_timestamp(tv);
3849 for (XMLNodeConstIterator child_it = t->children().begin();
3850 child_it != t->children().end(); child_it++)
3852 XMLNode *n = *child_it;
3855 if (n->name() == "MementoCommand" ||
3856 n->name() == "MementoUndoCommand" ||
3857 n->name() == "MementoRedoCommand") {
3859 if ((c = memento_command_factory(n))) {
3863 } else if (n->name() == "NoteDiffCommand") {
3864 PBD::ID id (n->property("midi-source")->value());
3865 boost::shared_ptr<MidiSource> midi_source =
3866 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3868 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3870 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3873 } else if (n->name() == "SysExDiffCommand") {
3875 PBD::ID id (n->property("midi-source")->value());
3876 boost::shared_ptr<MidiSource> midi_source =
3877 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3879 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3881 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3884 } else if (n->name() == "PatchChangeDiffCommand") {
3886 PBD::ID id (n->property("midi-source")->value());
3887 boost::shared_ptr<MidiSource> midi_source =
3888 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3890 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3892 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3895 } else if (n->name() == "StatefulDiffCommand") {
3896 if ((c = stateful_diff_command_factory (n))) {
3897 ut->add_command (c);
3900 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3911 Session::config_changed (std::string p, bool ours)
3917 if (p == "seamless-loop") {
3919 } else if (p == "rf-speed") {
3921 } else if (p == "auto-loop") {
3923 } else if (p == "session-monitoring") {
3925 } else if (p == "auto-input") {
3927 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3928 /* auto-input only makes a difference if we're rolling */
3929 set_track_monitor_input_status (!config.get_auto_input());
3932 } else if (p == "punch-in") {
3936 if ((location = _locations->auto_punch_location()) != 0) {
3938 if (config.get_punch_in ()) {
3939 replace_event (SessionEvent::PunchIn, location->start());
3941 remove_event (location->start(), SessionEvent::PunchIn);
3945 } else if (p == "punch-out") {
3949 if ((location = _locations->auto_punch_location()) != 0) {
3951 if (config.get_punch_out()) {
3952 replace_event (SessionEvent::PunchOut, location->end());
3954 clear_events (SessionEvent::PunchOut);
3958 } else if (p == "edit-mode") {
3960 Glib::Threads::Mutex::Lock lm (playlists->lock);
3962 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3963 (*i)->set_edit_mode (Config->get_edit_mode ());
3966 } else if (p == "use-video-sync") {
3968 waiting_for_sync_offset = config.get_use_video_sync();
3970 } else if (p == "mmc-control") {
3972 //poke_midi_thread ();
3974 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3976 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3978 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3980 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3982 } else if (p == "midi-control") {
3984 //poke_midi_thread ();
3986 } else if (p == "raid-path") {
3988 setup_raid_path (config.get_raid_path());
3990 } else if (p == "timecode-format") {
3994 } else if (p == "video-pullup") {
3998 } else if (p == "seamless-loop") {
4000 if (play_loop && transport_rolling()) {
4001 // to reset diskstreams etc
4002 request_play_loop (true);
4005 } else if (p == "rf-speed") {
4007 cumulative_rf_motion = 0;
4010 } else if (p == "click-sound") {
4012 setup_click_sounds (1);
4014 } else if (p == "click-emphasis-sound") {
4016 setup_click_sounds (-1);
4018 } else if (p == "clicking") {
4020 if (Config->get_clicking()) {
4021 if (_click_io && click_data) { // don't require emphasis data
4028 } else if (p == "click-record-only") {
4030 _click_rec_only = Config->get_click_record_only();
4032 } else if (p == "click-gain") {
4035 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
4038 } else if (p == "send-mtc") {
4040 if (Config->get_send_mtc ()) {
4041 /* mark us ready to send */
4042 next_quarter_frame_to_send = 0;
4045 } else if (p == "send-mmc") {
4047 _mmc->enable_send (Config->get_send_mmc ());
4049 } else if (p == "jack-time-master") {
4051 engine().reset_timebase ();
4053 } else if (p == "native-file-header-format") {
4055 if (!first_file_header_format_reset) {
4056 reset_native_file_format ();
4059 first_file_header_format_reset = false;
4061 } else if (p == "native-file-data-format") {
4063 if (!first_file_data_format_reset) {
4064 reset_native_file_format ();
4067 first_file_data_format_reset = false;
4069 } else if (p == "external-sync") {
4070 if (!config.get_external_sync()) {
4071 drop_sync_source ();
4073 switch_to_sync_source (Config->get_sync_source());
4075 } else if (p == "denormal-model") {
4077 } else if (p == "history-depth") {
4078 set_history_depth (Config->get_history_depth());
4079 } else if (p == "remote-model") {
4080 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
4083 } else if (p == "initial-program-change") {
4085 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
4088 buf[0] = MIDI::program; // channel zero by default
4089 buf[1] = (Config->get_initial_program_change() & 0x7f);
4091 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4093 } else if (p == "solo-mute-override") {
4094 // catch_up_on_solo_mute_override ();
4095 } else if (p == "listen-position" || p == "pfl-position") {
4096 listen_position_changed ();
4097 } else if (p == "solo-control-is-listen-control") {
4098 solo_control_mode_changed ();
4099 } else if (p == "solo-mute-gain") {
4100 _solo_cut_control->Changed (true, Controllable::NoGroup);
4101 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4102 last_timecode_valid = false;
4103 } else if (p == "playback-buffer-seconds") {
4104 AudioSource::allocate_working_buffers (frame_rate());
4105 } else if (p == "ltc-source-port") {
4106 reconnect_ltc_input ();
4107 } else if (p == "ltc-sink-port") {
4108 reconnect_ltc_output ();
4109 } else if (p == "timecode-generator-offset") {
4110 ltc_tx_parse_offset();
4111 } else if (p == "auto-return-target-list") {
4112 follow_playhead_priority ();
4119 Session::set_history_depth (uint32_t d)
4121 _history.set_depth (d);
4125 Session::load_diskstreams_2X (XMLNode const & node, int)
4128 XMLNodeConstIterator citer;
4130 clist = node.children();
4132 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4135 /* diskstreams added automatically by DiskstreamCreated handler */
4136 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4137 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4138 _diskstreams_2X.push_back (dsp);
4140 error << _("Session: unknown diskstream type in XML") << endmsg;
4144 catch (failed_constructor& err) {
4145 error << _("Session: could not load diskstream via XML state") << endmsg;
4153 /** Connect things to the MMC object */
4155 Session::setup_midi_machine_control ()
4157 _mmc = new MIDI::MachineControl;
4159 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4160 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4162 if (!async_out || !async_out) {
4166 /* XXXX argh, passing raw pointers back into libmidi++ */
4168 MIDI::Port* mmc_in = async_in.get();
4169 MIDI::Port* mmc_out = async_out.get();
4171 _mmc->set_ports (mmc_in, mmc_out);
4173 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4174 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4175 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4176 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4177 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4178 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4179 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4180 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4181 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4182 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4183 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4184 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4185 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4187 /* also handle MIDI SPP because its so common */
4189 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4190 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4191 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4194 boost::shared_ptr<Controllable>
4195 Session::solo_cut_control() const
4197 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4198 * controls in Ardour that currently get presented to the user in the GUI that require
4199 * access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4201 * its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4202 * it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4205 return _solo_cut_control;
4209 Session::save_snapshot_name (const std::string & n)
4211 /* assure Stateful::_instant_xml is loaded
4212 * add_instant_xml() only adds to existing data and defaults
4213 * to use an empty Tree otherwise
4215 instant_xml ("LastUsedSnapshot");
4217 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4218 last_used_snapshot->set_property ("name", n);
4219 add_instant_xml (*last_used_snapshot, false);
4223 Session::set_snapshot_name (const std::string & n)
4225 _current_snapshot_name = n;
4226 save_snapshot_name (n);
4230 Session::rename (const std::string& new_name)
4232 string legal_name = legalize_for_path (new_name);
4238 string const old_sources_root = _session_dir->sources_root();
4240 if (!_writable || (_state_of_the_state & CannotSave)) {
4241 error << _("Cannot rename read-only session.") << endmsg;
4242 return 0; // don't show "messed up" warning
4244 if (record_status() == Recording) {
4245 error << _("Cannot rename session while recording") << endmsg;
4246 return 0; // don't show "messed up" warning
4249 StateProtector stp (this);
4254 * interchange subdirectory
4258 * Backup files are left unchanged and not renamed.
4261 /* Windows requires that we close all files before attempting the
4262 * rename. This works on other platforms, but isn't necessary there.
4263 * Leave it in place for all platforms though, since it may help
4264 * catch issues that could arise if the way Source files work ever
4265 * change (since most developers are not using Windows).
4268 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4269 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4275 /* pass one: not 100% safe check that the new directory names don't
4279 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4283 /* this is a stupid hack because Glib::path_get_dirname() is
4284 * lexical-only, and so passing it /a/b/c/ gives a different
4285 * result than passing it /a/b/c ...
4288 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4289 oldstr = oldstr.substr (0, oldstr.length() - 1);
4292 string base = Glib::path_get_dirname (oldstr);
4294 newstr = Glib::build_filename (base, legal_name);
4296 cerr << "Looking for " << newstr << endl;
4298 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4299 cerr << " exists\n";
4308 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4314 /* this is a stupid hack because Glib::path_get_dirname() is
4315 * lexical-only, and so passing it /a/b/c/ gives a different
4316 * result than passing it /a/b/c ...
4319 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4320 oldstr = oldstr.substr (0, oldstr.length() - 1);
4323 string base = Glib::path_get_dirname (oldstr);
4324 newstr = Glib::build_filename (base, legal_name);
4326 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4328 cerr << "Rename " << oldstr << " => " << newstr << endl;
4329 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4330 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4331 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4335 /* Reset path in "session dirs" */
4340 /* reset primary SessionDirectory object */
4343 (*_session_dir) = newstr;
4348 /* now rename directory below session_dir/interchange */
4350 string old_interchange_dir;
4351 string new_interchange_dir;
4353 /* use newstr here because we renamed the path
4354 * (folder/directory) that used to be oldstr to newstr above
4357 v.push_back (newstr);
4358 v.push_back (interchange_dir_name);
4359 v.push_back (Glib::path_get_basename (oldstr));
4361 old_interchange_dir = Glib::build_filename (v);
4364 v.push_back (newstr);
4365 v.push_back (interchange_dir_name);
4366 v.push_back (legal_name);
4368 new_interchange_dir = Glib::build_filename (v);
4370 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4372 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4373 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4374 old_interchange_dir, new_interchange_dir,
4377 error << string_compose (_("renaming %s as %2 failed (%3)"),
4378 old_interchange_dir, new_interchange_dir,
4387 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4388 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4390 cerr << "Rename " << oldstr << " => " << newstr << endl;
4392 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4393 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4394 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4400 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4402 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4403 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4405 cerr << "Rename " << oldstr << " => " << newstr << endl;
4407 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4408 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4409 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4414 /* remove old name from recent sessions */
4415 remove_recent_sessions (_path);
4418 /* update file source paths */
4420 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4421 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4423 string p = fs->path ();
4424 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4426 SourceFactory::setup_peakfile(i->second, true);
4430 set_snapshot_name (new_name);
4435 /* save state again to get everything just right */
4437 save_state (_current_snapshot_name);
4439 /* add to recent sessions */
4441 store_recent_sessions (new_name, _path);
4447 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format, std::string& program_version)
4449 bool found_sr = false;
4450 bool found_data_format = false;
4451 program_version = "";
4453 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4457 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4461 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4464 xmlFreeParserCtxt(ctxt);
4468 xmlNodePtr node = xmlDocGetRootElement(doc);
4471 xmlFreeParserCtxt(ctxt);
4479 for (attr = node->properties; attr; attr = attr->next) {
4480 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4481 sample_rate = atoi ((char*)attr->children->content);
4486 node = node->children;
4487 while (node != NULL) {
4488 if (!strcmp((const char*) node->name, "ProgramVersion")) {
4489 xmlChar* val = xmlGetProp (node, (const xmlChar*)"modified-with");
4491 program_version = string ((const char*)val);
4492 size_t sep = program_version.find_first_of("-");
4493 if (sep != string::npos) {
4494 program_version = program_version.substr (0, sep);
4499 if (strcmp((const char*) node->name, "Config")) {
4503 for (node = node->children; node; node = node->next) {
4504 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4505 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4507 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4509 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4511 found_data_format = true;
4521 xmlFreeParserCtxt(ctxt);
4524 return !(found_sr && found_data_format); // zero if they are both found
4528 Session::get_snapshot_from_instant (const std::string& session_dir)
4530 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4532 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4537 if (!tree.read (instant_xml_path)) {
4541 XMLProperty const * prop;
4542 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4543 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4544 return prop->value();
4550 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4551 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4554 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4558 SourcePathMap source_path_map;
4560 boost::shared_ptr<AudioFileSource> afs;
4565 Glib::Threads::Mutex::Lock lm (source_lock);
4567 cerr << " total sources = " << sources.size();
4569 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4570 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4576 if (fs->within_session()) {
4580 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4581 source_path_map[fs->path()].push_back (fs);
4583 SeveralFileSources v;
4585 source_path_map.insert (make_pair (fs->path(), v));
4591 cerr << " fsources = " << total << endl;
4593 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4595 /* tell caller where we are */
4597 string old_path = i->first;
4599 callback (n, total, old_path);
4601 cerr << old_path << endl;
4605 switch (i->second.front()->type()) {
4606 case DataType::AUDIO:
4607 new_path = new_audio_source_path_for_embedded (old_path);
4610 case DataType::MIDI:
4611 /* XXX not implemented yet */
4615 if (new_path.empty()) {
4619 cerr << "Move " << old_path << " => " << new_path << endl;
4621 if (!copy_file (old_path, new_path)) {
4622 cerr << "failed !\n";
4626 /* make sure we stop looking in the external
4627 dir/folder. Remember, this is an all-or-nothing
4628 operations, it doesn't merge just some files.
4630 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4632 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4633 (*f)->set_path (new_path);
4638 save_state ("", false, false);
4644 bool accept_all_files (string const &, void *)
4650 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4652 /* 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.
4657 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4659 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4661 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4663 v.push_back (new_session_folder); /* full path */
4664 v.push_back (interchange_dir_name);
4665 v.push_back (new_session_path); /* just one directory/folder */
4666 v.push_back (typedir);
4667 v.push_back (Glib::path_get_basename (old_path));
4669 return Glib::build_filename (v);
4673 Session::save_as (SaveAs& saveas)
4675 vector<string> files;
4676 string current_folder = Glib::path_get_dirname (_path);
4677 string new_folder = legalize_for_path (saveas.new_name);
4678 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4679 int64_t total_bytes = 0;
4683 int32_t internal_file_cnt = 0;
4685 vector<string> do_not_copy_extensions;
4686 do_not_copy_extensions.push_back (statefile_suffix);
4687 do_not_copy_extensions.push_back (pending_suffix);
4688 do_not_copy_extensions.push_back (backup_suffix);
4689 do_not_copy_extensions.push_back (temp_suffix);
4690 do_not_copy_extensions.push_back (history_suffix);
4692 /* get total size */
4694 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4696 /* need to clear this because
4697 * find_files_matching_filter() is cumulative
4702 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4704 all += files.size();
4706 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4708 g_stat ((*i).c_str(), &gsb);
4709 total_bytes += gsb.st_size;
4713 /* save old values so we can switch back if we are not switching to the new session */
4715 string old_path = _path;
4716 string old_name = _name;
4717 string old_snapshot = _current_snapshot_name;
4718 string old_sd = _session_dir->root_path();
4719 vector<string> old_search_path[DataType::num_types];
4720 string old_config_search_path[DataType::num_types];
4722 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4723 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4724 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4725 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4727 /* switch session directory */
4729 (*_session_dir) = to_dir;
4731 /* create new tree */
4733 if (!_session_dir->create()) {
4734 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4739 /* copy all relevant files. Find each location in session_dirs,
4740 * and copy files from there to target.
4743 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4745 /* need to clear this because
4746 * find_files_matching_filter() is cumulative
4751 const size_t prefix_len = (*sd).path.size();
4753 /* Work just on the files within this session dir */
4755 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4757 /* add dir separator to protect against collisions with
4758 * track names (e.g. track named "audiofiles" or
4762 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4763 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4764 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4766 /* copy all the files. Handling is different for media files
4767 than others because of the *silly* subtree we have below the interchange
4768 folder. That really was a bad idea, but I'm not fixing it as part of
4769 implementing ::save_as().
4772 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4774 std::string from = *i;
4777 string filename = Glib::path_get_basename (from);
4778 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4779 if (filename == ".DS_STORE") {
4784 if (from.find (audiofile_dir_string) != string::npos) {
4786 /* audio file: only copy if asked */
4788 if (saveas.include_media && saveas.copy_media) {
4790 string to = make_new_media_path (*i, to_dir, new_folder);
4792 info << "media file copying from " << from << " to " << to << endmsg;
4794 if (!copy_file (from, to)) {
4795 throw Glib::FileError (Glib::FileError::IO_ERROR,
4796 string_compose(_("\ncopying \"%1\" failed !"), from));
4800 /* we found media files inside the session folder */
4802 internal_file_cnt++;
4804 } else if (from.find (midifile_dir_string) != string::npos) {
4806 /* midi file: always copy unless
4807 * creating an empty new session
4810 if (saveas.include_media) {
4812 string to = make_new_media_path (*i, to_dir, new_folder);
4814 info << "media file copying from " << from << " to " << to << endmsg;
4816 if (!copy_file (from, to)) {
4817 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4821 /* we found media files inside the session folder */
4823 internal_file_cnt++;
4825 } else if (from.find (analysis_dir_string) != string::npos) {
4827 /* make sure analysis dir exists in
4828 * new session folder, but we're not
4829 * copying analysis files here, see
4833 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4838 /* normal non-media file. Don't copy state, history, etc.
4841 bool do_copy = true;
4843 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4844 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4845 /* end of filename matches extension, do not copy file */
4851 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4852 /* don't copy peakfiles if
4853 * we're not copying media
4859 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4861 info << "attempting to make directory/folder " << to << endmsg;
4863 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4864 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4867 info << "attempting to copy " << from << " to " << to << endmsg;
4869 if (!copy_file (from, to)) {
4870 throw Glib::FileError (Glib::FileError::IO_ERROR,
4871 string_compose(_("\ncopying \"%1\" failed !"), from));
4876 /* measure file size even if we're not going to copy so that our Progress
4877 signals are correct, since we included these do-not-copy files
4878 in the computation of the total size and file count.
4882 g_stat (from.c_str(), &gsb);
4883 copied += gsb.st_size;
4886 double fraction = (double) copied / total_bytes;
4888 bool keep_going = true;
4890 if (saveas.copy_media) {
4892 /* no need or expectation of this if
4893 * media is not being copied, because
4894 * it will be fast(ish).
4897 /* tell someone "X percent, file M of N"; M is one-based */
4899 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4907 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4913 /* copy optional folders, if any */
4915 string old = plugins_dir ();
4916 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4917 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4918 copy_files (old, newdir);
4921 old = externals_dir ();
4922 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4923 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4924 copy_files (old, newdir);
4927 old = automation_dir ();
4928 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4929 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4930 copy_files (old, newdir);
4933 if (saveas.include_media) {
4935 if (saveas.copy_media) {
4936 #ifndef PLATFORM_WINDOWS
4937 /* There are problems with analysis files on
4938 * Windows, because they used a colon in their
4939 * names as late as 4.0. Colons are not legal
4940 * under Windows even if NTFS allows them.
4942 * This is a tricky problem to solve so for
4943 * just don't copy these files. They will be
4944 * regenerated as-needed anyway, subject to the
4945 * existing issue that the filenames will be
4946 * rejected by Windows, which is a separate
4947 * problem (though related).
4950 /* only needed if we are copying media, since the
4951 * analysis data refers to media data
4954 old = analysis_dir ();
4955 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4956 string newdir = Glib::build_filename (to_dir, "analysis");
4957 copy_files (old, newdir);
4959 #endif /* PLATFORM_WINDOWS */
4964 set_snapshot_name (saveas.new_name);
4965 _name = saveas.new_name;
4967 if (saveas.include_media && !saveas.copy_media) {
4969 /* reset search paths of the new session (which we're pretending to be right now) to
4970 include the original session search path, so we can still find all audio.
4973 if (internal_file_cnt) {
4974 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4975 ensure_search_path_includes (*s, DataType::AUDIO);
4976 cerr << "be sure to include " << *s << " for audio" << endl;
4979 /* we do not do this for MIDI because we copy
4980 all MIDI files if saveas.include_media is
4986 bool was_dirty = dirty ();
4988 save_default_options ();
4990 if (saveas.copy_media && saveas.copy_external) {
4991 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4992 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4996 saveas.final_session_folder_name = _path;
4998 store_recent_sessions (_name, _path);
5000 if (!saveas.switch_to) {
5002 /* save the new state */
5004 save_state ("", false, false, !saveas.include_media);
5006 /* switch back to the way things were */
5010 set_snapshot_name (old_snapshot);
5012 (*_session_dir) = old_sd;
5018 if (internal_file_cnt) {
5019 /* reset these to their original values */
5020 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5021 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5026 /* prune session dirs, and update disk space statistics
5031 session_dirs.clear ();
5032 session_dirs.push_back (sp);
5033 refresh_disk_space ();
5035 /* ensure that all existing tracks reset their current capture source paths
5037 reset_write_sources (true, true);
5039 /* creating new write sources marks the session as
5040 dirty. If the new session is empty, then
5041 save_state() thinks we're saving a template and will
5042 not mark the session as clean. So do that here,
5043 before we save state.
5046 if (!saveas.include_media) {
5047 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
5050 save_state ("", false, false, !saveas.include_media);
5052 /* the copying above was based on actually discovering files, not just iterating over the sources list.
5053 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
5056 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5057 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
5063 if (fs->within_session()) {
5064 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
5065 fs->set_path (newpath);
5070 } catch (Glib::FileError& e) {
5072 saveas.failure_message = e.what();
5074 /* recursively remove all the directories */
5076 remove_directory (to_dir);
5084 saveas.failure_message = _("unknown reason");
5086 /* recursively remove all the directories */
5088 remove_directory (to_dir);
5098 static void set_progress (Progress* p, size_t n, size_t t)
5100 p->set_progress (float (n) / float(t));
5104 Session::archive_session (const std::string& dest,
5105 const std::string& name,
5106 ArchiveEncode compress_audio,
5107 bool only_used_sources,
5110 if (dest.empty () || name.empty ()) {
5114 /* save current values */
5115 bool was_dirty = dirty ();
5116 string old_path = _path;
5117 string old_name = _name;
5118 string old_snapshot = _current_snapshot_name;
5119 string old_sd = _session_dir->root_path();
5120 string old_config_search_path[DataType::num_types];
5121 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5122 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5124 /* ensure that session-path is included in search-path */
5126 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5127 if ((*sd).path == old_path) {
5135 /* create temporary dir to save session to */
5136 #ifdef PLATFORM_WINDOWS
5137 char tmp[256] = "C:\\TEMP\\";
5138 GetTempPath (sizeof (tmp), tmp);
5140 char const* tmp = getenv("TMPDIR");
5145 if ((strlen (tmp) + 21) > 1024) {
5150 strcpy (tmptpl, tmp);
5151 strcat (tmptpl, "ardourarchive-XXXXXX");
5152 char* tmpdir = g_mkdtemp (tmptpl);
5158 std::string to_dir = std::string (tmpdir);
5160 /* switch session directory temporarily */
5161 (*_session_dir) = to_dir;
5163 if (!_session_dir->create()) {
5164 (*_session_dir) = old_sd;
5165 remove_directory (to_dir);
5169 /* prepare archive */
5170 string archive = Glib::build_filename (dest, name + ".tar.xz");
5172 PBD::ScopedConnectionList progress_connection;
5173 PBD::FileArchive ar (archive);
5175 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5178 /* collect files to archive */
5179 std::map<string,string> filemap;
5181 vector<string> do_not_copy_extensions;
5182 do_not_copy_extensions.push_back (statefile_suffix);
5183 do_not_copy_extensions.push_back (pending_suffix);
5184 do_not_copy_extensions.push_back (backup_suffix);
5185 do_not_copy_extensions.push_back (temp_suffix);
5186 do_not_copy_extensions.push_back (history_suffix);
5188 vector<string> blacklist_dirs;
5189 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5190 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5191 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5192 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5193 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5194 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5196 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5197 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5199 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5200 if (only_used_sources) {
5201 playlists->sync_all_regions_with_regions ();
5202 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5205 // collect audio sources for this session, calc total size for encoding
5206 // add option to only include *used* sources (see Session::cleanup_sources)
5207 size_t total_size = 0;
5209 Glib::Threads::Mutex::Lock lm (source_lock);
5210 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5211 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5212 if (!afs || afs->readable_length () == 0) {
5216 if (only_used_sources) {
5220 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5225 std::string from = afs->path();
5227 if (compress_audio != NO_ENCODE) {
5228 total_size += afs->readable_length ();
5230 if (afs->within_session()) {
5231 filemap[from] = make_new_media_path (from, name, name);
5233 filemap[from] = make_new_media_path (from, name, name);
5234 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5241 if (compress_audio != NO_ENCODE) {
5243 progress->set_progress (2); // set to "encoding"
5244 progress->set_progress (0);
5247 Glib::Threads::Mutex::Lock lm (source_lock);
5248 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5249 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5250 if (!afs || afs->readable_length () == 0) {
5254 if (only_used_sources) {
5258 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5263 orig_sources[afs] = afs->path();
5264 orig_gain[afs] = afs->gain();
5266 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5267 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5268 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5271 progress->descend ((float)afs->readable_length () / total_size);
5275 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5276 afs->replace_file (new_path);
5277 afs->set_gain (ns->gain(), true);
5280 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5284 progress->ascend ();
5290 progress->set_progress (-1); // set to "archiving"
5291 progress->set_progress (0);
5294 /* index files relevant for this session */
5295 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5296 vector<string> files;
5298 size_t prefix_len = (*sd).path.size();
5299 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5303 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5305 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5306 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5307 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5309 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5310 std::string from = *i;
5313 string filename = Glib::path_get_basename (from);
5314 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5315 if (filename == ".DS_STORE") {
5320 if (from.find (audiofile_dir_string) != string::npos) {
5322 } else if (from.find (midifile_dir_string) != string::npos) {
5323 filemap[from] = make_new_media_path (from, name, name);
5324 } else if (from.find (videofile_dir_string) != string::npos) {
5325 filemap[from] = make_new_media_path (from, name, name);
5327 bool do_copy = true;
5328 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5329 if (from.find (*v) != string::npos) {
5334 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5335 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5342 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5348 /* write session file */
5350 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5352 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5355 save_default_options ();
5357 size_t prefix_len = _path.size();
5358 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5362 /* collect session-state files */
5363 vector<string> files;
5364 do_not_copy_extensions.clear ();
5365 do_not_copy_extensions.push_back (history_suffix);
5367 blacklist_dirs.clear ();
5368 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5370 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5371 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5372 std::string from = *i;
5373 bool do_copy = true;
5374 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5375 if (from.find (*v) != string::npos) {
5380 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5381 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5387 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5391 /* restore original values */
5394 set_snapshot_name (old_snapshot);
5395 (*_session_dir) = old_sd;
5399 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5400 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5402 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5403 i->first->replace_file (i->second);
5405 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5406 i->first->set_gain (i->second, true);
5409 int rv = ar.create (filemap);
5410 remove_directory (to_dir);
5416 Session::undo (uint32_t n)
5418 if (actively_recording()) {
5426 Session::redo (uint32_t n)
5428 if (actively_recording()) {