2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
95 #include "ardour/lv2_plugin.h"
96 #include "ardour/midi_model.h"
97 #include "ardour/midi_patch_manager.h"
98 #include "ardour/midi_region.h"
99 #include "ardour/midi_scene_changer.h"
100 #include "ardour/midi_source.h"
101 #include "ardour/midi_track.h"
102 #include "ardour/pannable.h"
103 #include "ardour/playlist_factory.h"
104 #include "ardour/playlist_source.h"
105 #include "ardour/port.h"
106 #include "ardour/processor.h"
107 #include "ardour/progress.h"
108 #include "ardour/profile.h"
109 #include "ardour/proxy_controllable.h"
110 #include "ardour/recent_sessions.h"
111 #include "ardour/region_factory.h"
112 #include "ardour/revision.h"
113 #include "ardour/route_group.h"
114 #include "ardour/send.h"
115 #include "ardour/session.h"
116 #include "ardour/session_directory.h"
117 #include "ardour/session_metadata.h"
118 #include "ardour/session_playlists.h"
119 #include "ardour/session_state_utils.h"
120 #include "ardour/silentfilesource.h"
121 #include "ardour/sndfilesource.h"
122 #include "ardour/source_factory.h"
123 #include "ardour/speakers.h"
124 #include "ardour/template_utils.h"
125 #include "ardour/tempo.h"
126 #include "ardour/ticker.h"
127 #include "ardour/user_bundle.h"
128 #include "ardour/vca.h"
129 #include "ardour/vca_manager.h"
131 #include "control_protocol/control_protocol.h"
133 #include "LuaBridge/LuaBridge.h"
135 #include "pbd/i18n.h"
139 using namespace ARDOUR;
142 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
145 Session::pre_engine_init (string fullpath)
147 if (fullpath.empty()) {
149 throw failed_constructor();
152 /* discover canonical fullpath */
154 _path = canonical_path(fullpath);
157 if (Profile->get_trx() ) {
158 // Waves TracksLive has a usecase of session replacement with a new one.
159 // We should check session state file (<session_name>.ardour) existance
160 // to determine if the session is new or not
162 string full_session_name = Glib::build_filename( fullpath, _name );
163 full_session_name += statefile_suffix;
165 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
167 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
170 /* finish initialization that can't be done in a normal C++ constructor
174 timerclear (&last_mmc_step);
175 g_atomic_int_set (&processing_prohibited, 0);
176 g_atomic_int_set (&_record_status, Disabled);
177 g_atomic_int_set (&_playback_load, 100);
178 g_atomic_int_set (&_capture_load, 100);
180 _all_route_group->set_active (true, this);
181 interpolation.add_channel_to (0, 0);
183 if (config.get_use_video_sync()) {
184 waiting_for_sync_offset = true;
186 waiting_for_sync_offset = false;
189 last_rr_session_dir = session_dirs.begin();
191 set_history_depth (Config->get_history_depth());
193 /* default: assume simple stereo speaker configuration */
195 _speakers->setup_default_speakers (2);
197 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
198 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
199 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
200 add_controllable (_solo_cut_control);
202 /* These are all static "per-class" signals */
204 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
205 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
206 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
207 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
208 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
210 /* stop IO objects from doing stuff until we're ready for them */
212 Delivery::disable_panners ();
213 IO::disable_connecting ();
217 Session::post_engine_init ()
219 BootMessage (_("Set block size and sample rate"));
221 set_block_size (_engine.samples_per_cycle());
222 set_frame_rate (_engine.sample_rate());
224 BootMessage (_("Using configuration"));
226 _midi_ports = new MidiPortManager;
228 MIDISceneChanger* msc;
230 _scene_changer = msc = new MIDISceneChanger (*this);
231 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
232 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
234 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
235 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
237 setup_midi_machine_control ();
239 if (_butler->start_thread()) {
240 error << _("Butler did not start") << endmsg;
244 if (start_midi_thread ()) {
245 error << _("MIDI I/O thread did not start") << endmsg;
249 setup_click_sounds (0);
250 setup_midi_control ();
252 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
253 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
256 /* tempo map requires sample rate knowledge */
259 _tempo_map = new TempoMap (_current_frame_rate);
260 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
261 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::gui_tempo_map_changed, this));
263 /* MidiClock requires a tempo map */
266 midi_clock = new MidiClockTicker ();
267 midi_clock->set_session (this);
269 /* crossfades require sample rate knowledge */
271 SndFileSource::setup_standard_crossfades (*this, frame_rate());
272 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
274 AudioDiskstream::allocate_working_buffers();
275 refresh_disk_space ();
277 /* we're finally ready to call set_state() ... all objects have
278 * been created, the engine is running.
282 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
283 error << _("Could not set session state from XML") << endmsg;
287 // set_state() will call setup_raid_path(), but if it's a new session we need
288 // to call setup_raid_path() here.
289 setup_raid_path (_path);
294 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
295 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
297 Config->map_parameters (ff);
298 config.map_parameters (ft);
299 _butler->map_parameters ();
301 /* Reset all panners */
303 Delivery::reset_panners ();
305 /* this will cause the CPM to instantiate any protocols that are in use
306 * (or mandatory), which will pass it this Session, and then call
307 * set_state() on each instantiated protocol to match stored state.
310 ControlProtocolManager::instance().set_session (this);
312 /* This must be done after the ControlProtocolManager set_session above,
313 as it will set states for ports which the ControlProtocolManager creates.
316 // XXX set state of MIDI::Port's
317 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
319 /* And this must be done after the MIDI::Manager::set_port_states as
320 * it will try to make connections whose details are loaded by set_port_states.
325 /* Let control protocols know that we are now all connected, so they
326 * could start talking to surfaces if they want to.
329 ControlProtocolManager::instance().midi_connectivity_established ();
331 if (_is_new && !no_auto_connect()) {
332 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
333 auto_connect_master_bus ();
336 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
338 /* update latencies */
340 initialize_latencies ();
342 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
343 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
344 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
346 } catch (AudioEngine::PortRegistrationFailure& err) {
347 /* handle this one in a different way than all others, so that its clear what happened */
348 error << err.what() << endmsg;
350 } catch (std::exception const & e) {
351 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
354 error << _("Unknown exception during session setup") << endmsg;
358 BootMessage (_("Reset Remote Controls"));
360 // send_full_time_code (0);
361 _engine.transport_locate (0);
363 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
364 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
366 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
369 /* initial program change will be delivered later; see ::config_changed() */
371 _state_of_the_state = Clean;
373 Port::set_connecting_blocked (false);
375 DirtyChanged (); /* EMIT SIGNAL */
379 } else if (state_was_pending) {
381 remove_pending_capture_state ();
382 state_was_pending = false;
385 /* Now, finally, we can fill the playback buffers */
387 BootMessage (_("Filling playback buffers"));
389 boost::shared_ptr<RouteList> rl = routes.reader();
390 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
391 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
392 if (trk && !trk->hidden()) {
393 trk->seek (_transport_frame, true);
401 Session::session_loaded ()
405 _state_of_the_state = Clean;
407 DirtyChanged (); /* EMIT SIGNAL */
411 } else if (state_was_pending) {
413 remove_pending_capture_state ();
414 state_was_pending = false;
417 /* Now, finally, we can fill the playback buffers */
419 BootMessage (_("Filling playback buffers"));
420 force_locate (_transport_frame, false);
424 Session::raid_path () const
426 Searchpath raid_search_path;
428 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
429 raid_search_path += (*i).path;
432 return raid_search_path.to_string ();
436 Session::setup_raid_path (string path)
445 session_dirs.clear ();
447 Searchpath search_path(path);
448 Searchpath sound_search_path;
449 Searchpath midi_search_path;
451 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
453 sp.blocks = 0; // not needed
454 session_dirs.push_back (sp);
456 SessionDirectory sdir(sp.path);
458 sound_search_path += sdir.sound_path ();
459 midi_search_path += sdir.midi_path ();
462 // reset the round-robin soundfile path thingie
463 last_rr_session_dir = session_dirs.begin();
467 Session::path_is_within_session (const std::string& path)
469 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
470 if (PBD::path_is_within (i->path, path)) {
478 Session::ensure_subdirs ()
482 dir = session_directory().peak_path();
484 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
485 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
489 dir = session_directory().sound_path();
491 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
492 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
496 dir = session_directory().midi_path();
498 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
499 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
503 dir = session_directory().dead_path();
505 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
506 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
510 dir = session_directory().export_path();
512 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
513 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
517 dir = analysis_dir ();
519 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
520 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
524 dir = plugins_dir ();
526 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
527 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
531 dir = externals_dir ();
533 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
534 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
541 /** @param session_template directory containing session template, or empty.
542 * Caller must not hold process lock.
545 Session::create (const string& session_template, BusProfile* bus_profile)
547 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
548 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
552 if (ensure_subdirs ()) {
556 _writable = exists_and_writable (_path);
558 if (!session_template.empty()) {
559 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
561 FILE* in = g_fopen (in_path.c_str(), "rb");
564 /* no need to call legalize_for_path() since the string
565 * in session_template is already a legal path name
567 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
569 FILE* out = g_fopen (out_path.c_str(), "wb");
573 stringstream new_session;
576 size_t charsRead = fread (buf, sizeof(char), 1024, in);
579 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
584 if (charsRead == 0) {
587 new_session.write (buf, charsRead);
591 string file_contents = new_session.str();
592 size_t writeSize = file_contents.length();
593 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
594 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
602 if (!ARDOUR::Profile->get_trx()) {
603 /* Copy plugin state files from template to new session */
604 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
605 copy_recurse (template_plugins, plugins_dir ());
611 error << string_compose (_("Could not open %1 for writing session template"), out_path)
618 error << string_compose (_("Could not open session template %1 for reading"), in_path)
625 if (Profile->get_trx()) {
627 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
628 Remember that this is a brand new session. Sessions
629 loaded from saved state will get this range from the saved state.
632 set_session_range_location (0, 0);
634 /* Initial loop location, from absolute zero, length 10 seconds */
636 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
637 _locations->add (loc, true);
638 set_auto_loop_location (loc);
641 _state_of_the_state = Clean;
643 /* set up Master Out and Monitor Out if necessary */
648 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
650 // Waves Tracks: always create master bus for Tracks
651 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
652 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
660 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
661 r->input()->ensure_io (count, false, this);
662 r->output()->ensure_io (count, false, this);
668 /* prohibit auto-connect to master, because there isn't one */
669 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
673 add_routes (rl, false, false, false, PresentationInfo::max_order);
676 // Waves Tracks: Skip this. Always use autoconnection for Tracks
677 if (!ARDOUR::Profile->get_trx()) {
679 /* this allows the user to override settings with an environment variable.
682 if (no_auto_connect()) {
683 bus_profile->input_ac = AutoConnectOption (0);
684 bus_profile->output_ac = AutoConnectOption (0);
687 Config->set_input_auto_connect (bus_profile->input_ac);
688 Config->set_output_auto_connect (bus_profile->output_ac);
692 if (Config->get_use_monitor_bus() && bus_profile) {
693 add_monitor_section ();
700 Session::maybe_write_autosave()
702 if (dirty() && record_status() != Recording) {
703 save_state("", true);
708 Session::remove_pending_capture_state ()
710 std::string pending_state_file_path(_session_dir->root_path());
712 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
714 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
716 if (g_remove (pending_state_file_path.c_str()) != 0) {
717 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
718 pending_state_file_path, g_strerror (errno)) << endmsg;
722 /** Rename a state file.
723 * @param old_name Old snapshot name.
724 * @param new_name New snapshot name.
727 Session::rename_state (string old_name, string new_name)
729 if (old_name == _current_snapshot_name || old_name == _name) {
730 /* refuse to rename the current snapshot or the "main" one */
734 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
735 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
737 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
738 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
740 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
741 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
742 old_name, new_name, g_strerror(errno)) << endmsg;
746 /** Remove a state file.
747 * @param snapshot_name Snapshot name.
750 Session::remove_state (string snapshot_name)
752 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
753 // refuse to remove the current snapshot or the "main" one
757 std::string xml_path(_session_dir->root_path());
759 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
761 if (!create_backup_file (xml_path)) {
762 // don't remove it if a backup can't be made
763 // create_backup_file will log the error.
768 if (g_remove (xml_path.c_str()) != 0) {
769 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
770 xml_path, g_strerror (errno)) << endmsg;
774 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
776 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
778 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
781 std::string xml_path(_session_dir->root_path());
783 /* prevent concurrent saves from different threads */
785 Glib::Threads::Mutex::Lock lm (save_state_lock);
787 if (!_writable || (_state_of_the_state & CannotSave)) {
791 if (g_atomic_int_get(&_suspend_save)) {
795 _save_queued = false;
797 if (!_engine.connected ()) {
798 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
805 const int64_t save_start_time = g_get_monotonic_time();
808 /* tell sources we're saving first, in case they write out to a new file
809 * which should be saved with the state rather than the old one */
810 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
812 i->second->session_saved();
813 } catch (Evoral::SMF::FileError& e) {
814 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
818 SessionSaveUnderway (); /* EMIT SIGNAL */
820 bool mark_as_clean = true;
822 if (!snapshot_name.empty() && !switch_to_snapshot) {
823 mark_as_clean = false;
827 mark_as_clean = false;
828 tree.set_root (&get_template());
830 tree.set_root (&get_state());
833 if (snapshot_name.empty()) {
834 snapshot_name = _current_snapshot_name;
835 } else if (switch_to_snapshot) {
836 set_snapshot_name (snapshot_name);
839 assert (!snapshot_name.empty());
843 /* proper save: use statefile_suffix (.ardour in English) */
845 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
847 /* make a backup copy of the old file */
849 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
850 // create_backup_file will log the error
856 /* pending save: use pending_suffix (.pending in English) */
857 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
860 std::string tmp_path(_session_dir->root_path());
861 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
863 cerr << "actually writing state to " << tmp_path << endl;
865 if (!tree.write (tmp_path)) {
866 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
867 if (g_remove (tmp_path.c_str()) != 0) {
868 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
869 tmp_path, g_strerror (errno)) << endmsg;
875 cerr << "renaming state to " << xml_path << endl;
877 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
878 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
879 tmp_path, xml_path, g_strerror(errno)) << endmsg;
880 if (g_remove (tmp_path.c_str()) != 0) {
881 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
882 tmp_path, g_strerror (errno)) << endmsg;
890 save_history (snapshot_name);
893 bool was_dirty = dirty();
895 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
898 DirtyChanged (); /* EMIT SIGNAL */
902 StateSaved (snapshot_name); /* EMIT SIGNAL */
906 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
907 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
913 Session::restore_state (string snapshot_name)
915 if (load_state (snapshot_name) == 0) {
916 set_state (*state_tree->root(), Stateful::loading_state_version);
923 Session::load_state (string snapshot_name)
928 state_was_pending = false;
930 /* check for leftover pending state from a crashed capture attempt */
932 std::string xmlpath(_session_dir->root_path());
933 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
935 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
937 /* there is pending state from a crashed capture attempt */
939 boost::optional<int> r = AskAboutPendingState();
940 if (r.get_value_or (1)) {
941 state_was_pending = true;
945 if (!state_was_pending) {
946 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
949 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
950 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
951 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
952 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
957 state_tree = new XMLTree;
961 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
963 if (!state_tree->read (xmlpath)) {
964 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
970 XMLNode const & root (*state_tree->root());
972 if (root.name() != X_("Session")) {
973 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
979 XMLProperty const * prop;
981 if ((prop = root.property ("version")) == 0) {
982 /* no version implies very old version of Ardour */
983 Stateful::loading_state_version = 1000;
985 if (prop->value().find ('.') != string::npos) {
986 /* old school version format */
987 if (prop->value()[0] == '2') {
988 Stateful::loading_state_version = 2000;
990 Stateful::loading_state_version = 3000;
993 Stateful::loading_state_version = atoi (prop->value());
997 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
999 std::string backup_path(_session_dir->root_path());
1000 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1001 backup_path = Glib::build_filename (backup_path, backup_filename);
1003 // only create a backup for a given statefile version once
1005 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1007 VersionMismatch (xmlpath, backup_path);
1009 if (!copy_file (xmlpath, backup_path)) {;
1015 save_snapshot_name (snapshot_name);
1021 Session::load_options (const XMLNode& node)
1024 config.set_variables (node);
1029 Session::save_default_options ()
1031 return config.save_state();
1035 Session::get_state()
1041 Session::get_template()
1043 /* if we don't disable rec-enable, diskstreams
1044 will believe they need to store their capture
1045 sources in their state node.
1048 disable_record (false);
1050 return state(false);
1054 Session::state (bool full_state)
1057 XMLNode* node = new XMLNode("Session");
1061 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1062 node->add_property("version", buf);
1064 child = node->add_child ("ProgramVersion");
1065 child->add_property("created-with", created_with);
1067 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1068 child->add_property("modified-with", modified_with);
1070 /* store configuration settings */
1074 node->add_property ("name", _name);
1075 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1076 node->add_property ("sample-rate", buf);
1078 if (session_dirs.size() > 1) {
1082 vector<space_and_path>::iterator i = session_dirs.begin();
1083 vector<space_and_path>::iterator next;
1085 ++i; /* skip the first one */
1089 while (i != session_dirs.end()) {
1093 if (next != session_dirs.end()) {
1094 p += G_SEARCHPATH_SEPARATOR;
1103 child = node->add_child ("Path");
1104 child->add_content (p);
1108 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1110 /* save the ID counter */
1112 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1113 node->add_property ("id-counter", buf);
1115 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1116 node->add_property ("name-counter", buf);
1118 /* save the event ID counter */
1120 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1121 node->add_property ("event-counter", buf);
1123 /* save the VCA counter */
1125 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1126 node->add_property ("vca-counter", buf);
1128 /* various options */
1130 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1131 if (!midi_port_nodes.empty()) {
1132 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1133 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1134 midi_port_stuff->add_child_nocopy (**n);
1136 node->add_child_nocopy (*midi_port_stuff);
1139 XMLNode& cfgxml (config.get_variables ());
1141 /* exclude search-paths from template */
1142 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1143 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1144 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1146 node->add_child_nocopy (cfgxml);
1148 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1150 child = node->add_child ("Sources");
1153 Glib::Threads::Mutex::Lock sl (source_lock);
1155 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1157 /* Don't save information about non-file Sources, or
1158 * about non-destructive file sources that are empty
1159 * and unused by any regions.
1162 boost::shared_ptr<FileSource> fs;
1164 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1166 if (!fs->destructive()) {
1167 if (fs->empty() && !fs->used()) {
1172 child->add_child_nocopy (siter->second->get_state());
1177 child = node->add_child ("Regions");
1180 Glib::Threads::Mutex::Lock rl (region_lock);
1181 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1182 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1183 boost::shared_ptr<Region> r = i->second;
1184 /* only store regions not attached to playlists */
1185 if (r->playlist() == 0) {
1186 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1187 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1189 child->add_child_nocopy (r->get_state ());
1194 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1196 if (!cassocs.empty()) {
1197 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1199 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1201 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1202 i->first->id().print (buf, sizeof (buf));
1203 can->add_property (X_("copy"), buf);
1204 i->second->id().print (buf, sizeof (buf));
1205 can->add_property (X_("original"), buf);
1206 ca->add_child_nocopy (*can);
1216 node->add_child_nocopy (_locations->get_state());
1219 Locations loc (*this);
1220 // for a template, just create a new Locations, populate it
1221 // with the default start and end, and get the state for that.
1222 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1223 range->set (max_framepos, 0);
1225 XMLNode& locations_state = loc.get_state();
1227 if (ARDOUR::Profile->get_trx() && _locations) {
1228 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1229 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1230 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1231 locations_state.add_child_nocopy ((*i)->get_state ());
1235 node->add_child_nocopy (locations_state);
1238 child = node->add_child ("Bundles");
1240 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1241 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1242 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1244 child->add_child_nocopy (b->get_state());
1249 node->add_child_nocopy (_vca_manager->get_state());
1251 child = node->add_child ("Routes");
1253 boost::shared_ptr<RouteList> r = routes.reader ();
1255 RoutePublicOrderSorter cmp;
1256 RouteList public_order (*r);
1257 public_order.sort (cmp);
1259 /* the sort should have put the monitor out first */
1262 assert (_monitor_out == public_order.front());
1265 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1266 if (!(*i)->is_auditioner()) {
1268 child->add_child_nocopy ((*i)->get_state());
1270 child->add_child_nocopy ((*i)->get_template());
1276 playlists->add_state (node, full_state);
1278 child = node->add_child ("RouteGroups");
1279 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1280 child->add_child_nocopy ((*i)->get_state());
1284 XMLNode* gain_child = node->add_child ("Click");
1285 gain_child->add_child_nocopy (_click_io->state (full_state));
1286 gain_child->add_child_nocopy (_click_gain->state (full_state));
1290 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1291 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1295 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1296 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1299 node->add_child_nocopy (_speakers->get_state());
1300 node->add_child_nocopy (_tempo_map->get_state());
1301 node->add_child_nocopy (get_control_protocol_state());
1304 node->add_child_copy (*_extra_xml);
1308 Glib::Threads::Mutex::Lock lm (lua_lock);
1311 luabridge::LuaRef savedstate ((*_lua_save)());
1312 saved = savedstate.cast<std::string>();
1314 lua.collect_garbage ();
1317 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1318 std::string b64s (b64);
1321 XMLNode* script_node = new XMLNode (X_("Script"));
1322 script_node->add_property (X_("lua"), LUA_VERSION);
1323 script_node->add_content (b64s);
1324 node->add_child_nocopy (*script_node);
1331 Session::get_control_protocol_state ()
1333 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1334 return cpm.get_state();
1338 Session::set_state (const XMLNode& node, int version)
1343 XMLProperty const * prop;
1346 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1348 if (node.name() != X_("Session")) {
1349 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1353 if ((prop = node.property ("name")) != 0) {
1354 _name = prop->value ();
1357 if ((prop = node.property (X_("sample-rate"))) != 0) {
1359 _base_frame_rate = atoi (prop->value());
1360 _nominal_frame_rate = _base_frame_rate;
1362 assert (AudioEngine::instance()->running ());
1363 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1364 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1365 if (r.get_value_or (0)) {
1371 created_with = "unknown";
1372 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1373 if ((prop = child->property (X_("created-with"))) != 0) {
1374 created_with = prop->value ();
1378 setup_raid_path(_session_dir->root_path());
1380 if ((prop = node.property (X_("end-is-free"))) != 0) {
1381 _session_range_end_is_free = string_is_affirmative (prop->value());
1384 if ((prop = node.property (X_("id-counter"))) != 0) {
1386 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1387 ID::init_counter (x);
1389 /* old sessions used a timebased counter, so fake
1390 the startup ID counter based on a standard
1395 ID::init_counter (now);
1398 if ((prop = node.property (X_("name-counter"))) != 0) {
1399 init_name_id_counter (atoi (prop->value()));
1402 if ((prop = node.property (X_("event-counter"))) != 0) {
1403 Evoral::init_event_id_counter (atoi (prop->value()));
1406 if ((prop = node.property (X_("vca-counter"))) != 0) {
1408 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1409 VCA::set_next_vca_number (x);
1411 VCA::set_next_vca_number (1);
1414 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1415 _midi_ports->set_midi_port_states (child->children());
1418 IO::disable_connecting ();
1420 Stateful::save_extra_xml (node);
1422 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1423 load_options (*child);
1424 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1425 load_options (*child);
1427 error << _("Session: XML state has no options section") << endmsg;
1430 if (version >= 3000) {
1431 if ((child = find_named_node (node, "Metadata")) == 0) {
1432 warning << _("Session: XML state has no metadata section") << endmsg;
1433 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1438 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1439 _speakers->set_state (*child, version);
1442 if ((child = find_named_node (node, "Sources")) == 0) {
1443 error << _("Session: XML state has no sources section") << endmsg;
1445 } else if (load_sources (*child)) {
1449 if ((child = find_named_node (node, "TempoMap")) == 0) {
1450 error << _("Session: XML state has no Tempo Map section") << endmsg;
1452 } else if (_tempo_map->set_state (*child, version)) {
1456 if ((child = find_named_node (node, "Locations")) == 0) {
1457 error << _("Session: XML state has no locations section") << endmsg;
1459 } else if (_locations->set_state (*child, version)) {
1463 locations_changed ();
1465 if (_session_range_location) {
1466 AudioFileSource::set_header_position_offset (_session_range_location->start());
1469 if ((child = find_named_node (node, "Regions")) == 0) {
1470 error << _("Session: XML state has no Regions section") << endmsg;
1472 } else if (load_regions (*child)) {
1476 if ((child = find_named_node (node, "Playlists")) == 0) {
1477 error << _("Session: XML state has no playlists section") << endmsg;
1479 } else if (playlists->load (*this, *child)) {
1483 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1485 } else if (playlists->load_unused (*this, *child)) {
1489 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1490 if (load_compounds (*child)) {
1495 if (version >= 3000) {
1496 if ((child = find_named_node (node, "Bundles")) == 0) {
1497 warning << _("Session: XML state has no bundles section") << endmsg;
1500 /* We can't load Bundles yet as they need to be able
1501 to convert from port names to Port objects, which can't happen until
1503 _bundle_xml_node = new XMLNode (*child);
1507 if (version < 3000) {
1508 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1509 error << _("Session: XML state has no diskstreams section") << endmsg;
1511 } else if (load_diskstreams_2X (*child, version)) {
1516 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1517 _vca_manager->set_state (*child, version);
1520 if ((child = find_named_node (node, "Routes")) == 0) {
1521 error << _("Session: XML state has no routes section") << endmsg;
1523 } else if (load_routes (*child, version)) {
1527 /* Now that we have Routes and masters loaded, connect them if appropriate */
1529 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1531 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1532 _diskstreams_2X.clear ();
1534 if (version >= 3000) {
1536 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1537 error << _("Session: XML state has no route groups section") << endmsg;
1539 } else if (load_route_groups (*child, version)) {
1543 } else if (version < 3000) {
1545 if ((child = find_named_node (node, "EditGroups")) == 0) {
1546 error << _("Session: XML state has no edit groups section") << endmsg;
1548 } else if (load_route_groups (*child, version)) {
1552 if ((child = find_named_node (node, "MixGroups")) == 0) {
1553 error << _("Session: XML state has no mix groups section") << endmsg;
1555 } else if (load_route_groups (*child, version)) {
1560 if ((child = find_named_node (node, "Click")) == 0) {
1561 warning << _("Session: XML state has no click section") << endmsg;
1562 } else if (_click_io) {
1563 setup_click_state (&node);
1566 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1567 ControlProtocolManager::instance().set_state (*child, version);
1570 if ((child = find_named_node (node, "Script"))) {
1571 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1572 if (!(*n)->is_content ()) { continue; }
1574 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1576 Glib::Threads::Mutex::Lock lm (lua_lock);
1577 (*_lua_load)(std::string ((const char*)buf, size));
1578 } catch (luabridge::LuaException const& e) {
1579 cerr << "LuaException:" << e.what () << endl;
1585 update_route_record_state ();
1587 /* here beginneth the second phase ... */
1588 set_snapshot_name (_current_snapshot_name);
1590 StateReady (); /* EMIT SIGNAL */
1603 Session::load_routes (const XMLNode& node, int version)
1606 XMLNodeConstIterator niter;
1607 RouteList new_routes;
1609 nlist = node.children();
1613 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1615 boost::shared_ptr<Route> route;
1616 if (version < 3000) {
1617 route = XMLRouteFactory_2X (**niter, version);
1619 route = XMLRouteFactory (**niter, version);
1623 error << _("Session: cannot create Route from XML description.") << endmsg;
1627 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1629 new_routes.push_back (route);
1632 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1634 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1636 BootMessage (_("Finished adding tracks/busses"));
1641 boost::shared_ptr<Route>
1642 Session::XMLRouteFactory (const XMLNode& node, int version)
1644 boost::shared_ptr<Route> ret;
1646 if (node.name() != "Route") {
1650 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1652 DataType type = DataType::AUDIO;
1653 XMLProperty const * prop = node.property("default-type");
1656 type = DataType (prop->value());
1659 assert (type != DataType::NIL);
1663 boost::shared_ptr<Track> track;
1665 if (type == DataType::AUDIO) {
1666 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1668 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1671 if (track->init()) {
1675 if (track->set_state (node, version)) {
1679 BOOST_MARK_TRACK (track);
1683 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1684 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1686 if (r->init () == 0 && r->set_state (node, version) == 0) {
1687 BOOST_MARK_ROUTE (r);
1695 boost::shared_ptr<Route>
1696 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1698 boost::shared_ptr<Route> ret;
1700 if (node.name() != "Route") {
1704 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1706 ds_prop = node.property (X_("diskstream"));
1709 DataType type = DataType::AUDIO;
1710 XMLProperty const * prop = node.property("default-type");
1713 type = DataType (prop->value());
1716 assert (type != DataType::NIL);
1720 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1721 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1725 if (i == _diskstreams_2X.end()) {
1726 error << _("Could not find diskstream for route") << endmsg;
1727 return boost::shared_ptr<Route> ();
1730 boost::shared_ptr<Track> track;
1732 if (type == DataType::AUDIO) {
1733 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1735 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1738 if (track->init()) {
1742 if (track->set_state (node, version)) {
1746 track->set_diskstream (*i);
1748 BOOST_MARK_TRACK (track);
1752 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1753 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1755 if (r->init () == 0 && r->set_state (node, version) == 0) {
1756 BOOST_MARK_ROUTE (r);
1765 Session::load_regions (const XMLNode& node)
1768 XMLNodeConstIterator niter;
1769 boost::shared_ptr<Region> region;
1771 nlist = node.children();
1775 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1776 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1777 error << _("Session: cannot create Region from XML description.");
1778 XMLProperty const * name = (**niter).property("name");
1781 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1792 Session::load_compounds (const XMLNode& node)
1794 XMLNodeList calist = node.children();
1795 XMLNodeConstIterator caiter;
1796 XMLProperty const * caprop;
1798 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1799 XMLNode* ca = *caiter;
1803 if ((caprop = ca->property (X_("original"))) == 0) {
1806 orig_id = caprop->value();
1808 if ((caprop = ca->property (X_("copy"))) == 0) {
1811 copy_id = caprop->value();
1813 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1814 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1816 if (!orig || !copy) {
1817 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1823 RegionFactory::add_compound_association (orig, copy);
1830 Session::load_nested_sources (const XMLNode& node)
1833 XMLNodeConstIterator niter;
1835 nlist = node.children();
1837 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1838 if ((*niter)->name() == "Source") {
1840 /* it may already exist, so don't recreate it unnecessarily
1843 XMLProperty const * prop = (*niter)->property (X_("id"));
1845 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1849 ID source_id (prop->value());
1851 if (!source_by_id (source_id)) {
1854 SourceFactory::create (*this, **niter, true);
1856 catch (failed_constructor& err) {
1857 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1864 boost::shared_ptr<Region>
1865 Session::XMLRegionFactory (const XMLNode& node, bool full)
1867 XMLProperty const * type = node.property("type");
1871 const XMLNodeList& nlist = node.children();
1873 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1874 XMLNode *child = (*niter);
1875 if (child->name() == "NestedSource") {
1876 load_nested_sources (*child);
1880 if (!type || type->value() == "audio") {
1881 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1882 } else if (type->value() == "midi") {
1883 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1886 } catch (failed_constructor& err) {
1887 return boost::shared_ptr<Region> ();
1890 return boost::shared_ptr<Region> ();
1893 boost::shared_ptr<AudioRegion>
1894 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1896 XMLProperty const * prop;
1897 boost::shared_ptr<Source> source;
1898 boost::shared_ptr<AudioSource> as;
1900 SourceList master_sources;
1901 uint32_t nchans = 1;
1904 if (node.name() != X_("Region")) {
1905 return boost::shared_ptr<AudioRegion>();
1908 if ((prop = node.property (X_("channels"))) != 0) {
1909 nchans = atoi (prop->value().c_str());
1912 if ((prop = node.property ("name")) == 0) {
1913 cerr << "no name for this region\n";
1917 if ((prop = node.property (X_("source-0"))) == 0) {
1918 if ((prop = node.property ("source")) == 0) {
1919 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1920 return boost::shared_ptr<AudioRegion>();
1924 PBD::ID s_id (prop->value());
1926 if ((source = source_by_id (s_id)) == 0) {
1927 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1928 return boost::shared_ptr<AudioRegion>();
1931 as = boost::dynamic_pointer_cast<AudioSource>(source);
1933 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1934 return boost::shared_ptr<AudioRegion>();
1937 sources.push_back (as);
1939 /* pickup other channels */
1941 for (uint32_t n=1; n < nchans; ++n) {
1942 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1943 if ((prop = node.property (buf)) != 0) {
1945 PBD::ID id2 (prop->value());
1947 if ((source = source_by_id (id2)) == 0) {
1948 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1949 return boost::shared_ptr<AudioRegion>();
1952 as = boost::dynamic_pointer_cast<AudioSource>(source);
1954 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1955 return boost::shared_ptr<AudioRegion>();
1957 sources.push_back (as);
1961 for (uint32_t n = 0; n < nchans; ++n) {
1962 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1963 if ((prop = node.property (buf)) != 0) {
1965 PBD::ID id2 (prop->value());
1967 if ((source = source_by_id (id2)) == 0) {
1968 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1969 return boost::shared_ptr<AudioRegion>();
1972 as = boost::dynamic_pointer_cast<AudioSource>(source);
1974 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1975 return boost::shared_ptr<AudioRegion>();
1977 master_sources.push_back (as);
1982 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1984 /* a final detail: this is the one and only place that we know how long missing files are */
1986 if (region->whole_file()) {
1987 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1988 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1990 sfp->set_length (region->length());
1995 if (!master_sources.empty()) {
1996 if (master_sources.size() != nchans) {
1997 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1999 region->set_master_sources (master_sources);
2007 catch (failed_constructor& err) {
2008 return boost::shared_ptr<AudioRegion>();
2012 boost::shared_ptr<MidiRegion>
2013 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2015 XMLProperty const * prop;
2016 boost::shared_ptr<Source> source;
2017 boost::shared_ptr<MidiSource> ms;
2020 if (node.name() != X_("Region")) {
2021 return boost::shared_ptr<MidiRegion>();
2024 if ((prop = node.property ("name")) == 0) {
2025 cerr << "no name for this region\n";
2029 if ((prop = node.property (X_("source-0"))) == 0) {
2030 if ((prop = node.property ("source")) == 0) {
2031 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2032 return boost::shared_ptr<MidiRegion>();
2036 PBD::ID s_id (prop->value());
2038 if ((source = source_by_id (s_id)) == 0) {
2039 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2040 return boost::shared_ptr<MidiRegion>();
2043 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2045 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2046 return boost::shared_ptr<MidiRegion>();
2049 sources.push_back (ms);
2052 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2053 /* a final detail: this is the one and only place that we know how long missing files are */
2055 if (region->whole_file()) {
2056 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2057 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2059 sfp->set_length (region->length());
2067 catch (failed_constructor& err) {
2068 return boost::shared_ptr<MidiRegion>();
2073 Session::get_sources_as_xml ()
2076 XMLNode* node = new XMLNode (X_("Sources"));
2077 Glib::Threads::Mutex::Lock lm (source_lock);
2079 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2080 node->add_child_nocopy (i->second->get_state());
2087 Session::reset_write_sources (bool mark_write_complete, bool force)
2089 boost::shared_ptr<RouteList> rl = routes.reader();
2090 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2091 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2093 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2094 tr->reset_write_sources(mark_write_complete, force);
2095 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2101 Session::load_sources (const XMLNode& node)
2104 XMLNodeConstIterator niter;
2105 boost::shared_ptr<Source> source; /* don't need this but it stops some
2106 * versions of gcc complaining about
2107 * discarded return values.
2110 nlist = node.children();
2114 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2117 if ((source = XMLSourceFactory (**niter)) == 0) {
2118 error << _("Session: cannot create Source from XML description.") << endmsg;
2121 } catch (MissingSource& err) {
2125 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2126 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2127 PROGRAM_NAME) << endmsg;
2131 if (!no_questions_about_missing_files) {
2132 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2137 switch (user_choice) {
2139 /* user added a new search location, so try again */
2144 /* user asked to quit the entire session load
2149 no_questions_about_missing_files = true;
2153 no_questions_about_missing_files = true;
2160 case DataType::AUDIO:
2161 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2164 case DataType::MIDI:
2165 /* The MIDI file is actually missing so
2166 * just create a new one in the same
2167 * location. Do not announce its
2171 if (!Glib::path_is_absolute (err.path)) {
2172 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2174 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2179 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2180 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2181 /* reset ID to match the missing one */
2182 source->set_id (**niter);
2183 /* Now we can announce it */
2184 SourceFactory::SourceCreated (source);
2195 boost::shared_ptr<Source>
2196 Session::XMLSourceFactory (const XMLNode& node)
2198 if (node.name() != "Source") {
2199 return boost::shared_ptr<Source>();
2203 /* note: do peak building in another thread when loading session state */
2204 return SourceFactory::create (*this, node, true);
2207 catch (failed_constructor& err) {
2208 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2209 return boost::shared_ptr<Source>();
2214 Session::save_template (string template_name, bool replace_existing)
2216 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2220 bool absolute_path = Glib::path_is_absolute (template_name);
2222 /* directory to put the template in */
2223 std::string template_dir_path;
2225 if (!absolute_path) {
2226 std::string user_template_dir(user_template_directory());
2228 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2229 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2230 user_template_dir, g_strerror (errno)) << endmsg;
2234 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2236 template_dir_path = template_name;
2239 if (!ARDOUR::Profile->get_trx()) {
2240 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2241 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2242 template_dir_path) << endmsg;
2246 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2247 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2248 template_dir_path, g_strerror (errno)) << endmsg;
2254 std::string template_file_path;
2256 if (ARDOUR::Profile->get_trx()) {
2257 template_file_path = template_name;
2259 if (absolute_path) {
2260 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2262 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2266 SessionSaveUnderway (); /* EMIT SIGNAL */
2271 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2272 tree.set_root (&get_template());
2275 if (!tree.write (template_file_path)) {
2276 error << _("template not saved") << endmsg;
2280 store_recent_templates (template_file_path);
2286 Session::refresh_disk_space ()
2288 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2290 Glib::Threads::Mutex::Lock lm (space_lock);
2292 /* get freespace on every FS that is part of the session path */
2294 _total_free_4k_blocks = 0;
2295 _total_free_4k_blocks_uncertain = false;
2297 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2298 #if defined(__NetBSD__)
2299 struct statvfs statfsbuf;
2301 statvfs (i->path.c_str(), &statfsbuf);
2303 struct statfs statfsbuf;
2305 statfs (i->path.c_str(), &statfsbuf);
2307 double const scale = statfsbuf.f_bsize / 4096.0;
2309 /* See if this filesystem is read-only */
2310 struct statvfs statvfsbuf;
2311 statvfs (i->path.c_str(), &statvfsbuf);
2313 /* f_bavail can be 0 if it is undefined for whatever
2314 filesystem we are looking at; Samba shares mounted
2315 via GVFS are an example of this.
2317 if (statfsbuf.f_bavail == 0) {
2318 /* block count unknown */
2320 i->blocks_unknown = true;
2321 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2322 /* read-only filesystem */
2324 i->blocks_unknown = false;
2326 /* read/write filesystem with known space */
2327 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2328 i->blocks_unknown = false;
2331 _total_free_4k_blocks += i->blocks;
2332 if (i->blocks_unknown) {
2333 _total_free_4k_blocks_uncertain = true;
2336 #elif defined PLATFORM_WINDOWS
2337 vector<string> scanned_volumes;
2338 vector<string>::iterator j;
2339 vector<space_and_path>::iterator i;
2340 DWORD nSectorsPerCluster, nBytesPerSector,
2341 nFreeClusters, nTotalClusters;
2345 _total_free_4k_blocks = 0;
2347 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2348 strncpy (disk_drive, (*i).path.c_str(), 3);
2352 volume_found = false;
2353 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2355 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2356 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2357 i->blocks = (uint32_t)(nFreeBytes / 4096);
2359 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2360 if (0 == j->compare(disk_drive)) {
2361 volume_found = true;
2366 if (!volume_found) {
2367 scanned_volumes.push_back(disk_drive);
2368 _total_free_4k_blocks += i->blocks;
2373 if (0 == _total_free_4k_blocks) {
2374 strncpy (disk_drive, path().c_str(), 3);
2377 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2379 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2380 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2381 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2388 Session::get_best_session_directory_for_new_audio ()
2390 vector<space_and_path>::iterator i;
2391 string result = _session_dir->root_path();
2393 /* handle common case without system calls */
2395 if (session_dirs.size() == 1) {
2399 /* OK, here's the algorithm we're following here:
2401 We want to select which directory to use for
2402 the next file source to be created. Ideally,
2403 we'd like to use a round-robin process so as to
2404 get maximum performance benefits from splitting
2405 the files across multiple disks.
2407 However, in situations without much diskspace, an
2408 RR approach may end up filling up a filesystem
2409 with new files while others still have space.
2410 Its therefore important to pay some attention to
2411 the freespace in the filesystem holding each
2412 directory as well. However, if we did that by
2413 itself, we'd keep creating new files in the file
2414 system with the most space until it was as full
2415 as all others, thus negating any performance
2416 benefits of this RAID-1 like approach.
2418 So, we use a user-configurable space threshold. If
2419 there are at least 2 filesystems with more than this
2420 much space available, we use RR selection between them.
2421 If not, then we pick the filesystem with the most space.
2423 This gets a good balance between the two
2427 refresh_disk_space ();
2429 int free_enough = 0;
2431 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2432 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2437 if (free_enough >= 2) {
2438 /* use RR selection process, ensuring that the one
2442 i = last_rr_session_dir;
2445 if (++i == session_dirs.end()) {
2446 i = session_dirs.begin();
2449 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2450 SessionDirectory sdir(i->path);
2451 if (sdir.create ()) {
2453 last_rr_session_dir = i;
2458 } while (i != last_rr_session_dir);
2462 /* pick FS with the most freespace (and that
2463 seems to actually work ...)
2466 vector<space_and_path> sorted;
2467 space_and_path_ascending_cmp cmp;
2469 sorted = session_dirs;
2470 sort (sorted.begin(), sorted.end(), cmp);
2472 for (i = sorted.begin(); i != sorted.end(); ++i) {
2473 SessionDirectory sdir(i->path);
2474 if (sdir.create ()) {
2476 last_rr_session_dir = i;
2486 Session::automation_dir () const
2488 return Glib::build_filename (_path, automation_dir_name);
2492 Session::analysis_dir () const
2494 return Glib::build_filename (_path, analysis_dir_name);
2498 Session::plugins_dir () const
2500 return Glib::build_filename (_path, plugins_dir_name);
2504 Session::externals_dir () const
2506 return Glib::build_filename (_path, externals_dir_name);
2510 Session::load_bundles (XMLNode const & node)
2512 XMLNodeList nlist = node.children();
2513 XMLNodeConstIterator niter;
2517 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2518 if ((*niter)->name() == "InputBundle") {
2519 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2520 } else if ((*niter)->name() == "OutputBundle") {
2521 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2523 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2532 Session::load_route_groups (const XMLNode& node, int version)
2534 XMLNodeList nlist = node.children();
2535 XMLNodeConstIterator niter;
2539 if (version >= 3000) {
2541 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2542 if ((*niter)->name() == "RouteGroup") {
2543 RouteGroup* rg = new RouteGroup (*this, "");
2544 add_route_group (rg);
2545 rg->set_state (**niter, version);
2549 } else if (version < 3000) {
2551 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2552 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2553 RouteGroup* rg = new RouteGroup (*this, "");
2554 add_route_group (rg);
2555 rg->set_state (**niter, version);
2564 state_file_filter (const string &str, void* /*arg*/)
2566 return (str.length() > strlen(statefile_suffix) &&
2567 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2571 remove_end(string state)
2573 string statename(state);
2575 string::size_type start,end;
2576 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2577 statename = statename.substr (start+1);
2580 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2581 end = statename.length();
2584 return string(statename.substr (0, end));
2588 Session::possible_states (string path)
2590 vector<string> states;
2591 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2593 transform(states.begin(), states.end(), states.begin(), remove_end);
2595 sort (states.begin(), states.end());
2601 Session::possible_states () const
2603 return possible_states(_path);
2607 Session::add_route_group (RouteGroup* g)
2609 _route_groups.push_back (g);
2610 route_group_added (g); /* EMIT SIGNAL */
2612 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2613 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2614 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2620 Session::remove_route_group (RouteGroup& rg)
2622 list<RouteGroup*>::iterator i;
2624 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2625 _route_groups.erase (i);
2628 route_group_removed (); /* EMIT SIGNAL */
2632 /** Set a new order for our route groups, without adding or removing any.
2633 * @param groups Route group list in the new order.
2636 Session::reorder_route_groups (list<RouteGroup*> groups)
2638 _route_groups = groups;
2640 route_groups_reordered (); /* EMIT SIGNAL */
2646 Session::route_group_by_name (string name)
2648 list<RouteGroup *>::iterator i;
2650 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2651 if ((*i)->name() == name) {
2659 Session::all_route_group() const
2661 return *_all_route_group;
2665 Session::add_commands (vector<Command*> const & cmds)
2667 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2673 Session::add_command (Command* const cmd)
2675 assert (_current_trans);
2676 DEBUG_UNDO_HISTORY (
2677 string_compose ("Current Undo Transaction %1, adding command: %2",
2678 _current_trans->name (),
2680 _current_trans->add_command (cmd);
2683 PBD::StatefulDiffCommand*
2684 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2686 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2692 Session::begin_reversible_command (const string& name)
2694 begin_reversible_command (g_quark_from_string (name.c_str ()));
2697 /** Begin a reversible command using a GQuark to identify it.
2698 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2699 * but there must be as many begin...()s as there are commit...()s.
2702 Session::begin_reversible_command (GQuark q)
2704 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2705 to hold all the commands that are committed. This keeps the order of
2706 commands correct in the history.
2709 if (_current_trans == 0) {
2710 DEBUG_UNDO_HISTORY (string_compose (
2711 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2713 /* start a new transaction */
2714 assert (_current_trans_quarks.empty ());
2715 _current_trans = new UndoTransaction();
2716 _current_trans->set_name (g_quark_to_string (q));
2718 DEBUG_UNDO_HISTORY (
2719 string_compose ("Begin Reversible Command, current transaction: %1",
2720 _current_trans->name ()));
2723 _current_trans_quarks.push_front (q);
2727 Session::abort_reversible_command ()
2729 if (_current_trans != 0) {
2730 DEBUG_UNDO_HISTORY (
2731 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2732 _current_trans->clear();
2733 delete _current_trans;
2735 _current_trans_quarks.clear();
2740 Session::commit_reversible_command (Command *cmd)
2742 assert (_current_trans);
2743 assert (!_current_trans_quarks.empty ());
2748 DEBUG_UNDO_HISTORY (
2749 string_compose ("Current Undo Transaction %1, adding command: %2",
2750 _current_trans->name (),
2752 _current_trans->add_command (cmd);
2755 DEBUG_UNDO_HISTORY (
2756 string_compose ("Commit Reversible Command, current transaction: %1",
2757 _current_trans->name ()));
2759 _current_trans_quarks.pop_front ();
2761 if (!_current_trans_quarks.empty ()) {
2762 DEBUG_UNDO_HISTORY (
2763 string_compose ("Commit Reversible Command, transaction is not "
2764 "top-level, current transaction: %1",
2765 _current_trans->name ()));
2766 /* the transaction we're committing is not the top-level one */
2770 if (_current_trans->empty()) {
2771 /* no commands were added to the transaction, so just get rid of it */
2772 DEBUG_UNDO_HISTORY (
2773 string_compose ("Commit Reversible Command, No commands were "
2774 "added to current transaction: %1",
2775 _current_trans->name ()));
2776 delete _current_trans;
2781 gettimeofday (&now, 0);
2782 _current_trans->set_timestamp (now);
2784 _history.add (_current_trans);
2789 accept_all_audio_files (const string& path, void* /*arg*/)
2791 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2795 if (!AudioFileSource::safe_audio_file_extension (path)) {
2803 accept_all_midi_files (const string& path, void* /*arg*/)
2805 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2809 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2810 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2811 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2815 accept_all_state_files (const string& path, void* /*arg*/)
2817 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2821 std::string const statefile_ext (statefile_suffix);
2822 if (path.length() >= statefile_ext.length()) {
2823 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2830 Session::find_all_sources (string path, set<string>& result)
2835 if (!tree.read (path)) {
2839 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2844 XMLNodeConstIterator niter;
2846 nlist = node->children();
2850 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2852 XMLProperty const * prop;
2854 if ((prop = (*niter)->property (X_("type"))) == 0) {
2858 DataType type (prop->value());
2860 if ((prop = (*niter)->property (X_("name"))) == 0) {
2864 if (Glib::path_is_absolute (prop->value())) {
2865 /* external file, ignore */
2873 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2874 result.insert (found_path);
2882 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2884 vector<string> state_files;
2886 string this_snapshot_path;
2892 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2893 ripped = ripped.substr (0, ripped.length() - 1);
2896 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2898 if (state_files.empty()) {
2903 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2904 this_snapshot_path += statefile_suffix;
2906 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2908 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2910 if (exclude_this_snapshot && *i == this_snapshot_path) {
2911 cerr << "\texcluded\n";
2916 if (find_all_sources (*i, result) < 0) {
2924 struct RegionCounter {
2925 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2926 AudioSourceList::iterator iter;
2927 boost::shared_ptr<Region> region;
2930 RegionCounter() : count (0) {}
2934 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2936 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2937 return r.get_value_or (1);
2941 Session::cleanup_regions ()
2943 bool removed = false;
2944 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2946 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2948 uint32_t used = playlists->region_use_count (i->second);
2950 if (used == 0 && !i->second->automatic ()) {
2951 boost::weak_ptr<Region> w = i->second;
2954 RegionFactory::map_remove (w);
2961 // re-check to remove parent references of compound regions
2962 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2963 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2967 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2968 if (0 == playlists->region_use_count (i->second)) {
2969 boost::weak_ptr<Region> w = i->second;
2971 RegionFactory::map_remove (w);
2978 /* dump the history list */
2985 Session::can_cleanup_peakfiles () const
2987 if (deletion_in_progress()) {
2990 if (!_writable || (_state_of_the_state & CannotSave)) {
2991 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2994 if (record_status() == Recording) {
2995 error << _("Cannot cleanup peak-files while recording") << endmsg;
3002 Session::cleanup_peakfiles ()
3004 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3009 assert (can_cleanup_peakfiles ());
3010 assert (!peaks_cleanup_in_progres());
3012 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3014 int timeout = 5000; // 5 seconds
3015 while (!SourceFactory::files_with_peaks.empty()) {
3016 Glib::usleep (1000);
3017 if (--timeout < 0) {
3018 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3019 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3024 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3025 boost::shared_ptr<AudioSource> as;
3026 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3027 as->close_peakfile();
3031 PBD::clear_directory (session_directory().peak_path());
3033 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3035 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3036 boost::shared_ptr<AudioSource> as;
3037 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3038 SourceFactory::setup_peakfile(as, true);
3045 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3047 pl->deep_sources (*all_sources);
3051 Session::cleanup_sources (CleanupReport& rep)
3053 // FIXME: needs adaptation to midi
3055 vector<boost::shared_ptr<Source> > dead_sources;
3058 vector<string> candidates;
3059 vector<string> unused;
3060 set<string> sources_used_by_all_snapshots;
3067 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3069 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3071 /* this is mostly for windows which doesn't allow file
3072 * renaming if the file is in use. But we don't special
3073 * case it because we need to know if this causes
3074 * problems, and the easiest way to notice that is to
3075 * keep it in place for all platforms.
3078 request_stop (false);
3080 _butler->wait_until_finished ();
3082 /* consider deleting all unused playlists */
3084 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3089 /* sync the "all regions" property of each playlist with its current state
3092 playlists->sync_all_regions_with_regions ();
3094 /* find all un-used sources */
3099 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3101 SourceMap::iterator tmp;
3106 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3110 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3111 dead_sources.push_back (i->second);
3112 i->second->drop_references ();
3118 /* build a list of all the possible audio directories for the session */
3120 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3121 SessionDirectory sdir ((*i).path);
3122 asp += sdir.sound_path();
3124 audio_path += asp.to_string();
3127 /* build a list of all the possible midi directories for the session */
3129 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3130 SessionDirectory sdir ((*i).path);
3131 msp += sdir.midi_path();
3133 midi_path += msp.to_string();
3135 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3136 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3138 /* add sources from all other snapshots as "used", but don't use this
3139 snapshot because the state file on disk still references sources we
3140 may have already dropped.
3143 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3145 /* Although the region factory has a list of all regions ever created
3146 * for this session, we're only interested in regions actually in
3147 * playlists right now. So merge all playlist regions lists together.
3149 * This will include the playlists used within compound regions.
3152 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3154 /* add our current source list
3157 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3158 boost::shared_ptr<FileSource> fs;
3159 SourceMap::iterator tmp = i;
3162 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3168 /* this is mostly for windows which doesn't allow file
3169 * renaming if the file is in use. But we do not special
3170 * case it because we need to know if this causes
3171 * problems, and the easiest way to notice that is to
3172 * keep it in place for all platforms.
3177 if (!fs->is_stub()) {
3179 /* Note that we're checking a list of all
3180 * sources across all snapshots with the list
3181 * of sources used by this snapshot.
3184 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3185 /* this source is in use by this snapshot */
3186 sources_used_by_all_snapshots.insert (fs->path());
3187 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3189 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3190 /* this source is NOT in use by this snapshot
3193 /* remove all related regions from RegionFactory master list
3196 RegionFactory::remove_regions_using_source (i->second);
3198 /* remove from our current source list
3199 * also. We may not remove it from
3200 * disk, because it may be used by
3201 * other snapshots, but it isn't used inside this
3202 * snapshot anymore, so we don't need a
3213 /* now check each candidate source to see if it exists in the list of
3214 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3217 cerr << "Candidates: " << candidates.size() << endl;
3218 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3220 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3225 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3227 tmppath1 = canonical_path (spath);
3228 tmppath2 = canonical_path ((*i));
3230 cerr << "\t => " << tmppath2 << endl;
3232 if (tmppath1 == tmppath2) {
3239 unused.push_back (spath);
3243 cerr << "Actually unused: " << unused.size() << endl;
3245 if (unused.empty()) {
3251 /* now try to move all unused files into the "dead" directory(ies) */
3253 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3258 /* don't move the file across filesystems, just
3259 stick it in the `dead_dir_name' directory
3260 on whichever filesystem it was already on.
3263 if ((*x).find ("/sounds/") != string::npos) {
3265 /* old school, go up 1 level */
3267 newpath = Glib::path_get_dirname (*x); // "sounds"
3268 newpath = Glib::path_get_dirname (newpath); // "session-name"
3272 /* new school, go up 4 levels */
3274 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3275 newpath = Glib::path_get_dirname (newpath); // "session-name"
3276 newpath = Glib::path_get_dirname (newpath); // "interchange"
3277 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3280 newpath = Glib::build_filename (newpath, dead_dir_name);
3282 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3283 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3287 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3289 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3291 /* the new path already exists, try versioning */
3293 char buf[PATH_MAX+1];
3297 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3300 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3301 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3305 if (version == 999) {
3306 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3310 newpath = newpath_v;
3315 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3316 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3317 newpath, g_strerror (errno)) << endmsg;
3321 /* see if there an easy to find peakfile for this file, and remove it.
3324 string base = Glib::path_get_basename (*x);
3325 base += "%A"; /* this is what we add for the channel suffix of all native files,
3326 or for the first channel of embedded files. it will miss
3327 some peakfiles for other channels
3329 string peakpath = construct_peak_filepath (base);
3331 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3332 if (::g_unlink (peakpath.c_str ()) != 0) {
3333 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3334 g_strerror (errno)) << endmsg;
3335 /* try to back out */
3336 ::g_rename (newpath.c_str (), _path.c_str ());
3341 rep.paths.push_back (*x);
3342 rep.space += statbuf.st_size;
3345 /* dump the history list */
3349 /* save state so we don't end up a session file
3350 referring to non-existent sources.
3357 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3363 Session::cleanup_trash_sources (CleanupReport& rep)
3365 // FIXME: needs adaptation for MIDI
3367 vector<space_and_path>::iterator i;
3373 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3375 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3377 clear_directory (dead_dir, &rep.space, &rep.paths);
3384 Session::set_dirty ()
3386 /* never mark session dirty during loading */
3388 if (_state_of_the_state & Loading) {
3392 bool was_dirty = dirty();
3394 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3398 DirtyChanged(); /* EMIT SIGNAL */
3404 Session::set_clean ()
3406 bool was_dirty = dirty();
3408 _state_of_the_state = Clean;
3412 DirtyChanged(); /* EMIT SIGNAL */
3417 Session::set_deletion_in_progress ()
3419 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3423 Session::clear_deletion_in_progress ()
3425 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3429 Session::add_controllable (boost::shared_ptr<Controllable> c)
3431 /* this adds a controllable to the list managed by the Session.
3432 this is a subset of those managed by the Controllable class
3433 itself, and represents the only ones whose state will be saved
3434 as part of the session.
3437 Glib::Threads::Mutex::Lock lm (controllables_lock);
3438 controllables.insert (c);
3441 struct null_deleter { void operator()(void const *) const {} };
3444 Session::remove_controllable (Controllable* c)
3446 if (_state_of_the_state & Deletion) {
3450 Glib::Threads::Mutex::Lock lm (controllables_lock);
3452 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3454 if (x != controllables.end()) {
3455 controllables.erase (x);
3459 boost::shared_ptr<Controllable>
3460 Session::controllable_by_id (const PBD::ID& id)
3462 Glib::Threads::Mutex::Lock lm (controllables_lock);
3464 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3465 if ((*i)->id() == id) {
3470 return boost::shared_ptr<Controllable>();
3473 boost::shared_ptr<Controllable>
3474 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3476 boost::shared_ptr<Controllable> c;
3477 boost::shared_ptr<Stripable> s;
3478 boost::shared_ptr<Route> r;
3480 switch (desc.top_level_type()) {
3481 case ControllableDescriptor::NamedRoute:
3483 std::string str = desc.top_level_name();
3485 if (str == "Master" || str == "master") {
3487 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3489 } else if (str == "auditioner") {
3492 s = route_by_name (desc.top_level_name());
3498 case ControllableDescriptor::PresentationOrderRoute:
3499 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3502 case ControllableDescriptor::PresentationOrderTrack:
3503 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3506 case ControllableDescriptor::PresentationOrderBus:
3507 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3510 case ControllableDescriptor::PresentationOrderVCA:
3511 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3514 case ControllableDescriptor::SelectionCount:
3515 s = route_by_selected_count (desc.selection_id());
3523 r = boost::dynamic_pointer_cast<Route> (s);
3525 switch (desc.subtype()) {
3526 case ControllableDescriptor::Gain:
3527 c = s->gain_control ();
3530 case ControllableDescriptor::Trim:
3531 c = s->trim_control ();
3534 case ControllableDescriptor::Solo:
3535 c = s->solo_control();
3538 case ControllableDescriptor::Mute:
3539 c = s->mute_control();
3542 case ControllableDescriptor::Recenable:
3543 c = s->rec_enable_control ();
3546 case ControllableDescriptor::PanDirection:
3547 c = s->pan_azimuth_control();
3550 case ControllableDescriptor::PanWidth:
3551 c = s->pan_width_control();
3554 case ControllableDescriptor::PanElevation:
3555 c = s->pan_elevation_control();
3558 case ControllableDescriptor::Balance:
3559 /* XXX simple pan control */
3562 case ControllableDescriptor::PluginParameter:
3564 uint32_t plugin = desc.target (0);
3565 uint32_t parameter_index = desc.target (1);
3567 /* revert to zero based counting */
3573 if (parameter_index > 0) {
3581 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3584 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3585 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3590 case ControllableDescriptor::SendGain: {
3591 uint32_t send = desc.target (0);
3598 c = r->send_level_controllable (send);
3603 /* relax and return a null pointer */
3611 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3614 Stateful::add_instant_xml (node, _path);
3617 if (write_to_config) {
3618 Config->add_instant_xml (node);
3623 Session::instant_xml (const string& node_name)
3625 return Stateful::instant_xml (node_name, _path);
3629 Session::save_history (string snapshot_name)
3637 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3638 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3642 if (snapshot_name.empty()) {
3643 snapshot_name = _current_snapshot_name;
3646 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3647 const string backup_filename = history_filename + backup_suffix;
3648 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3649 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3651 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3652 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3653 error << _("could not backup old history file, current history not saved") << endmsg;
3658 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3660 if (!tree.write (xml_path))
3662 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3664 if (g_remove (xml_path.c_str()) != 0) {
3665 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3666 xml_path, g_strerror (errno)) << endmsg;
3668 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3669 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3670 backup_path, g_strerror (errno)) << endmsg;
3680 Session::restore_history (string snapshot_name)
3684 if (snapshot_name.empty()) {
3685 snapshot_name = _current_snapshot_name;
3688 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3689 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3691 info << "Loading history from " << xml_path << endmsg;
3693 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3694 info << string_compose (_("%1: no history file \"%2\" for this session."),
3695 _name, xml_path) << endmsg;
3699 if (!tree.read (xml_path)) {
3700 error << string_compose (_("Could not understand session history file \"%1\""),
3701 xml_path) << endmsg;
3708 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3711 UndoTransaction* ut = new UndoTransaction ();
3714 ut->set_name(t->property("name")->value());
3715 stringstream ss(t->property("tv-sec")->value());
3717 ss.str(t->property("tv-usec")->value());
3719 ut->set_timestamp(tv);
3721 for (XMLNodeConstIterator child_it = t->children().begin();
3722 child_it != t->children().end(); child_it++)
3724 XMLNode *n = *child_it;
3727 if (n->name() == "MementoCommand" ||
3728 n->name() == "MementoUndoCommand" ||
3729 n->name() == "MementoRedoCommand") {
3731 if ((c = memento_command_factory(n))) {
3735 } else if (n->name() == "NoteDiffCommand") {
3736 PBD::ID id (n->property("midi-source")->value());
3737 boost::shared_ptr<MidiSource> midi_source =
3738 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3740 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3742 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3745 } else if (n->name() == "SysExDiffCommand") {
3747 PBD::ID id (n->property("midi-source")->value());
3748 boost::shared_ptr<MidiSource> midi_source =
3749 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3751 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3753 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3756 } else if (n->name() == "PatchChangeDiffCommand") {
3758 PBD::ID id (n->property("midi-source")->value());
3759 boost::shared_ptr<MidiSource> midi_source =
3760 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3762 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3764 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3767 } else if (n->name() == "StatefulDiffCommand") {
3768 if ((c = stateful_diff_command_factory (n))) {
3769 ut->add_command (c);
3772 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3783 Session::config_changed (std::string p, bool ours)
3789 if (p == "seamless-loop") {
3791 } else if (p == "rf-speed") {
3793 } else if (p == "auto-loop") {
3795 } else if (p == "auto-input") {
3797 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3798 /* auto-input only makes a difference if we're rolling */
3799 set_track_monitor_input_status (!config.get_auto_input());
3802 } else if (p == "punch-in") {
3806 if ((location = _locations->auto_punch_location()) != 0) {
3808 if (config.get_punch_in ()) {
3809 replace_event (SessionEvent::PunchIn, location->start());
3811 remove_event (location->start(), SessionEvent::PunchIn);
3815 } else if (p == "punch-out") {
3819 if ((location = _locations->auto_punch_location()) != 0) {
3821 if (config.get_punch_out()) {
3822 replace_event (SessionEvent::PunchOut, location->end());
3824 clear_events (SessionEvent::PunchOut);
3828 } else if (p == "edit-mode") {
3830 Glib::Threads::Mutex::Lock lm (playlists->lock);
3832 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3833 (*i)->set_edit_mode (Config->get_edit_mode ());
3836 } else if (p == "use-video-sync") {
3838 waiting_for_sync_offset = config.get_use_video_sync();
3840 } else if (p == "mmc-control") {
3842 //poke_midi_thread ();
3844 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3846 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3848 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3850 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3852 } else if (p == "midi-control") {
3854 //poke_midi_thread ();
3856 } else if (p == "raid-path") {
3858 setup_raid_path (config.get_raid_path());
3860 } else if (p == "timecode-format") {
3864 } else if (p == "video-pullup") {
3868 } else if (p == "seamless-loop") {
3870 if (play_loop && transport_rolling()) {
3871 // to reset diskstreams etc
3872 request_play_loop (true);
3875 } else if (p == "rf-speed") {
3877 cumulative_rf_motion = 0;
3880 } else if (p == "click-sound") {
3882 setup_click_sounds (1);
3884 } else if (p == "click-emphasis-sound") {
3886 setup_click_sounds (-1);
3888 } else if (p == "clicking") {
3890 if (Config->get_clicking()) {
3891 if (_click_io && click_data) { // don't require emphasis data
3898 } else if (p == "click-gain") {
3901 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3904 } else if (p == "send-mtc") {
3906 if (Config->get_send_mtc ()) {
3907 /* mark us ready to send */
3908 next_quarter_frame_to_send = 0;
3911 } else if (p == "send-mmc") {
3913 _mmc->enable_send (Config->get_send_mmc ());
3915 } else if (p == "midi-feedback") {
3917 session_midi_feedback = Config->get_midi_feedback();
3919 } else if (p == "jack-time-master") {
3921 engine().reset_timebase ();
3923 } else if (p == "native-file-header-format") {
3925 if (!first_file_header_format_reset) {
3926 reset_native_file_format ();
3929 first_file_header_format_reset = false;
3931 } else if (p == "native-file-data-format") {
3933 if (!first_file_data_format_reset) {
3934 reset_native_file_format ();
3937 first_file_data_format_reset = false;
3939 } else if (p == "external-sync") {
3940 if (!config.get_external_sync()) {
3941 drop_sync_source ();
3943 switch_to_sync_source (Config->get_sync_source());
3945 } else if (p == "denormal-model") {
3947 } else if (p == "history-depth") {
3948 set_history_depth (Config->get_history_depth());
3949 } else if (p == "remote-model") {
3950 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3953 } else if (p == "initial-program-change") {
3955 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3958 buf[0] = MIDI::program; // channel zero by default
3959 buf[1] = (Config->get_initial_program_change() & 0x7f);
3961 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3963 } else if (p == "solo-mute-override") {
3964 // catch_up_on_solo_mute_override ();
3965 } else if (p == "listen-position" || p == "pfl-position") {
3966 listen_position_changed ();
3967 } else if (p == "solo-control-is-listen-control") {
3968 solo_control_mode_changed ();
3969 } else if (p == "solo-mute-gain") {
3970 _solo_cut_control->Changed (true, Controllable::NoGroup);
3971 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3972 last_timecode_valid = false;
3973 } else if (p == "playback-buffer-seconds") {
3974 AudioSource::allocate_working_buffers (frame_rate());
3975 } else if (p == "ltc-source-port") {
3976 reconnect_ltc_input ();
3977 } else if (p == "ltc-sink-port") {
3978 reconnect_ltc_output ();
3979 } else if (p == "timecode-generator-offset") {
3980 ltc_tx_parse_offset();
3981 } else if (p == "auto-return-target-list") {
3982 follow_playhead_priority ();
3989 Session::set_history_depth (uint32_t d)
3991 _history.set_depth (d);
3995 Session::load_diskstreams_2X (XMLNode const & node, int)
3998 XMLNodeConstIterator citer;
4000 clist = node.children();
4002 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4005 /* diskstreams added automatically by DiskstreamCreated handler */
4006 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4007 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4008 _diskstreams_2X.push_back (dsp);
4010 error << _("Session: unknown diskstream type in XML") << endmsg;
4014 catch (failed_constructor& err) {
4015 error << _("Session: could not load diskstream via XML state") << endmsg;
4023 /** Connect things to the MMC object */
4025 Session::setup_midi_machine_control ()
4027 _mmc = new MIDI::MachineControl;
4029 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4030 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4032 if (!async_out || !async_out) {
4036 /* XXXX argh, passing raw pointers back into libmidi++ */
4038 MIDI::Port* mmc_in = async_in.get();
4039 MIDI::Port* mmc_out = async_out.get();
4041 _mmc->set_ports (mmc_in, mmc_out);
4043 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4044 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4045 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4046 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4047 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4048 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4049 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4050 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4051 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4052 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4053 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4054 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4055 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4057 /* also handle MIDI SPP because its so common */
4059 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4060 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4061 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4064 boost::shared_ptr<Controllable>
4065 Session::solo_cut_control() const
4067 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4068 controls in Ardour that currently get presented to the user in the GUI that require
4069 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4071 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4072 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4076 return _solo_cut_control;
4080 Session::save_snapshot_name (const std::string & n)
4082 /* assure Stateful::_instant_xml is loaded
4083 * add_instant_xml() only adds to existing data and defaults
4084 * to use an empty Tree otherwise
4086 instant_xml ("LastUsedSnapshot");
4088 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4089 last_used_snapshot->add_property ("name", string(n));
4090 add_instant_xml (*last_used_snapshot, false);
4094 Session::set_snapshot_name (const std::string & n)
4096 _current_snapshot_name = n;
4097 save_snapshot_name (n);
4101 Session::rename (const std::string& new_name)
4103 string legal_name = legalize_for_path (new_name);
4109 string const old_sources_root = _session_dir->sources_root();
4111 if (!_writable || (_state_of_the_state & CannotSave)) {
4112 error << _("Cannot rename read-only session.") << endmsg;
4113 return 0; // don't show "messed up" warning
4115 if (record_status() == Recording) {
4116 error << _("Cannot rename session while recording") << endmsg;
4117 return 0; // don't show "messed up" warning
4120 StateProtector stp (this);
4125 * interchange subdirectory
4129 * Backup files are left unchanged and not renamed.
4132 /* Windows requires that we close all files before attempting the
4133 * rename. This works on other platforms, but isn't necessary there.
4134 * Leave it in place for all platforms though, since it may help
4135 * catch issues that could arise if the way Source files work ever
4136 * change (since most developers are not using Windows).
4139 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4140 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4146 /* pass one: not 100% safe check that the new directory names don't
4150 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4154 /* this is a stupid hack because Glib::path_get_dirname() is
4155 * lexical-only, and so passing it /a/b/c/ gives a different
4156 * result than passing it /a/b/c ...
4159 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4160 oldstr = oldstr.substr (0, oldstr.length() - 1);
4163 string base = Glib::path_get_dirname (oldstr);
4165 newstr = Glib::build_filename (base, legal_name);
4167 cerr << "Looking for " << newstr << endl;
4169 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4170 cerr << " exists\n";
4179 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4185 /* this is a stupid hack because Glib::path_get_dirname() is
4186 * lexical-only, and so passing it /a/b/c/ gives a different
4187 * result than passing it /a/b/c ...
4190 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4191 oldstr = oldstr.substr (0, oldstr.length() - 1);
4194 string base = Glib::path_get_dirname (oldstr);
4195 newstr = Glib::build_filename (base, legal_name);
4197 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4199 cerr << "Rename " << oldstr << " => " << newstr << endl;
4200 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4201 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4202 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4206 /* Reset path in "session dirs" */
4211 /* reset primary SessionDirectory object */
4214 (*_session_dir) = newstr;
4219 /* now rename directory below session_dir/interchange */
4221 string old_interchange_dir;
4222 string new_interchange_dir;
4224 /* use newstr here because we renamed the path
4225 * (folder/directory) that used to be oldstr to newstr above
4228 v.push_back (newstr);
4229 v.push_back (interchange_dir_name);
4230 v.push_back (Glib::path_get_basename (oldstr));
4232 old_interchange_dir = Glib::build_filename (v);
4235 v.push_back (newstr);
4236 v.push_back (interchange_dir_name);
4237 v.push_back (legal_name);
4239 new_interchange_dir = Glib::build_filename (v);
4241 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4243 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4244 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4245 old_interchange_dir, new_interchange_dir,
4248 error << string_compose (_("renaming %s as %2 failed (%3)"),
4249 old_interchange_dir, new_interchange_dir,
4258 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4259 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4261 cerr << "Rename " << oldstr << " => " << newstr << endl;
4263 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4264 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4265 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4271 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4273 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4274 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4276 cerr << "Rename " << oldstr << " => " << newstr << endl;
4278 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4279 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4280 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4285 /* remove old name from recent sessions */
4286 remove_recent_sessions (_path);
4289 /* update file source paths */
4291 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4292 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4294 string p = fs->path ();
4295 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4297 SourceFactory::setup_peakfile(i->second, true);
4301 set_snapshot_name (new_name);
4306 /* save state again to get everything just right */
4308 save_state (_current_snapshot_name);
4310 /* add to recent sessions */
4312 store_recent_sessions (new_name, _path);
4318 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4320 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4324 if (!tree.read (xmlpath)) {
4332 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4335 bool found_sr = false;
4336 bool found_data_format = false;
4338 if (get_session_info_from_path (tree, xmlpath)) {
4344 XMLProperty const * prop;
4345 XMLNode const * root (tree.root());
4347 if ((prop = root->property (X_("sample-rate"))) != 0) {
4348 sample_rate = atoi (prop->value());
4352 const XMLNodeList& children (root->children());
4353 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4354 const XMLNode* child = *c;
4355 if (child->name() == "Config") {
4356 const XMLNodeList& options (child->children());
4357 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4358 XMLNode const * option = *oc;
4359 XMLProperty const * name = option->property("name");
4365 if (name->value() == "native-file-data-format") {
4366 XMLProperty const * value = option->property ("value");
4368 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4370 found_data_format = true;
4376 if (found_data_format) {
4381 return !(found_sr && found_data_format); // zero if they are both found
4385 Session::get_snapshot_from_instant (const std::string& session_dir)
4387 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4389 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4394 if (!tree.read (instant_xml_path)) {
4398 XMLProperty const * prop;
4399 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4400 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4401 return prop->value();
4407 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4408 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4411 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4415 SourcePathMap source_path_map;
4417 boost::shared_ptr<AudioFileSource> afs;
4422 Glib::Threads::Mutex::Lock lm (source_lock);
4424 cerr << " total sources = " << sources.size();
4426 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4427 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4433 if (fs->within_session()) {
4437 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4438 source_path_map[fs->path()].push_back (fs);
4440 SeveralFileSources v;
4442 source_path_map.insert (make_pair (fs->path(), v));
4448 cerr << " fsources = " << total << endl;
4450 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4452 /* tell caller where we are */
4454 string old_path = i->first;
4456 callback (n, total, old_path);
4458 cerr << old_path << endl;
4462 switch (i->second.front()->type()) {
4463 case DataType::AUDIO:
4464 new_path = new_audio_source_path_for_embedded (old_path);
4467 case DataType::MIDI:
4468 /* XXX not implemented yet */
4472 if (new_path.empty()) {
4476 cerr << "Move " << old_path << " => " << new_path << endl;
4478 if (!copy_file (old_path, new_path)) {
4479 cerr << "failed !\n";
4483 /* make sure we stop looking in the external
4484 dir/folder. Remember, this is an all-or-nothing
4485 operations, it doesn't merge just some files.
4487 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4489 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4490 (*f)->set_path (new_path);
4495 save_state ("", false, false);
4501 bool accept_all_files (string const &, void *)
4507 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4509 /* 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.
4514 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4516 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4518 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4520 v.push_back (new_session_folder); /* full path */
4521 v.push_back (interchange_dir_name);
4522 v.push_back (new_session_path); /* just one directory/folder */
4523 v.push_back (typedir);
4524 v.push_back (Glib::path_get_basename (old_path));
4526 return Glib::build_filename (v);
4530 Session::save_as (SaveAs& saveas)
4532 vector<string> files;
4533 string current_folder = Glib::path_get_dirname (_path);
4534 string new_folder = legalize_for_path (saveas.new_name);
4535 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4536 int64_t total_bytes = 0;
4540 int32_t internal_file_cnt = 0;
4542 vector<string> do_not_copy_extensions;
4543 do_not_copy_extensions.push_back (statefile_suffix);
4544 do_not_copy_extensions.push_back (pending_suffix);
4545 do_not_copy_extensions.push_back (backup_suffix);
4546 do_not_copy_extensions.push_back (temp_suffix);
4547 do_not_copy_extensions.push_back (history_suffix);
4549 /* get total size */
4551 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4553 /* need to clear this because
4554 * find_files_matching_filter() is cumulative
4559 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4561 all += files.size();
4563 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4565 g_stat ((*i).c_str(), &gsb);
4566 total_bytes += gsb.st_size;
4570 /* save old values so we can switch back if we are not switching to the new session */
4572 string old_path = _path;
4573 string old_name = _name;
4574 string old_snapshot = _current_snapshot_name;
4575 string old_sd = _session_dir->root_path();
4576 vector<string> old_search_path[DataType::num_types];
4577 string old_config_search_path[DataType::num_types];
4579 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4580 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4581 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4582 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4584 /* switch session directory */
4586 (*_session_dir) = to_dir;
4588 /* create new tree */
4590 if (!_session_dir->create()) {
4591 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4596 /* copy all relevant files. Find each location in session_dirs,
4597 * and copy files from there to target.
4600 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4602 /* need to clear this because
4603 * find_files_matching_filter() is cumulative
4608 const size_t prefix_len = (*sd).path.size();
4610 /* Work just on the files within this session dir */
4612 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4614 /* add dir separator to protect against collisions with
4615 * track names (e.g. track named "audiofiles" or
4619 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4620 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4621 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4623 /* copy all the files. Handling is different for media files
4624 than others because of the *silly* subtree we have below the interchange
4625 folder. That really was a bad idea, but I'm not fixing it as part of
4626 implementing ::save_as().
4629 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4631 std::string from = *i;
4634 string filename = Glib::path_get_basename (from);
4635 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4636 if (filename == ".DS_STORE") {
4641 if (from.find (audiofile_dir_string) != string::npos) {
4643 /* audio file: only copy if asked */
4645 if (saveas.include_media && saveas.copy_media) {
4647 string to = make_new_media_path (*i, to_dir, new_folder);
4649 info << "media file copying from " << from << " to " << to << endmsg;
4651 if (!copy_file (from, to)) {
4652 throw Glib::FileError (Glib::FileError::IO_ERROR,
4653 string_compose(_("\ncopying \"%1\" failed !"), from));
4657 /* we found media files inside the session folder */
4659 internal_file_cnt++;
4661 } else if (from.find (midifile_dir_string) != string::npos) {
4663 /* midi file: always copy unless
4664 * creating an empty new session
4667 if (saveas.include_media) {
4669 string to = make_new_media_path (*i, to_dir, new_folder);
4671 info << "media file copying from " << from << " to " << to << endmsg;
4673 if (!copy_file (from, to)) {
4674 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4678 /* we found media files inside the session folder */
4680 internal_file_cnt++;
4682 } else if (from.find (analysis_dir_string) != string::npos) {
4684 /* make sure analysis dir exists in
4685 * new session folder, but we're not
4686 * copying analysis files here, see
4690 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4695 /* normal non-media file. Don't copy state, history, etc.
4698 bool do_copy = true;
4700 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4701 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4702 /* end of filename matches extension, do not copy file */
4708 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4709 /* don't copy peakfiles if
4710 * we're not copying media
4716 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4718 info << "attempting to make directory/folder " << to << endmsg;
4720 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4721 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4724 info << "attempting to copy " << from << " to " << to << endmsg;
4726 if (!copy_file (from, to)) {
4727 throw Glib::FileError (Glib::FileError::IO_ERROR,
4728 string_compose(_("\ncopying \"%1\" failed !"), from));
4733 /* measure file size even if we're not going to copy so that our Progress
4734 signals are correct, since we included these do-not-copy files
4735 in the computation of the total size and file count.
4739 g_stat (from.c_str(), &gsb);
4740 copied += gsb.st_size;
4743 double fraction = (double) copied / total_bytes;
4745 bool keep_going = true;
4747 if (saveas.copy_media) {
4749 /* no need or expectation of this if
4750 * media is not being copied, because
4751 * it will be fast(ish).
4754 /* tell someone "X percent, file M of N"; M is one-based */
4756 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4764 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4770 /* copy optional folders, if any */
4772 string old = plugins_dir ();
4773 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4774 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4775 copy_files (old, newdir);
4778 old = externals_dir ();
4779 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4780 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4781 copy_files (old, newdir);
4784 old = automation_dir ();
4785 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4786 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4787 copy_files (old, newdir);
4790 if (saveas.include_media) {
4792 if (saveas.copy_media) {
4793 #ifndef PLATFORM_WINDOWS
4794 /* There are problems with analysis files on
4795 * Windows, because they used a colon in their
4796 * names as late as 4.0. Colons are not legal
4797 * under Windows even if NTFS allows them.
4799 * This is a tricky problem to solve so for
4800 * just don't copy these files. They will be
4801 * regenerated as-needed anyway, subject to the
4802 * existing issue that the filenames will be
4803 * rejected by Windows, which is a separate
4804 * problem (though related).
4807 /* only needed if we are copying media, since the
4808 * analysis data refers to media data
4811 old = analysis_dir ();
4812 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4813 string newdir = Glib::build_filename (to_dir, "analysis");
4814 copy_files (old, newdir);
4816 #endif /* PLATFORM_WINDOWS */
4822 set_snapshot_name (saveas.new_name);
4823 _name = saveas.new_name;
4825 if (saveas.include_media && !saveas.copy_media) {
4827 /* reset search paths of the new session (which we're pretending to be right now) to
4828 include the original session search path, so we can still find all audio.
4831 if (internal_file_cnt) {
4832 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4833 ensure_search_path_includes (*s, DataType::AUDIO);
4834 cerr << "be sure to include " << *s << " for audio" << endl;
4837 /* we do not do this for MIDI because we copy
4838 all MIDI files if saveas.include_media is
4844 bool was_dirty = dirty ();
4846 save_state ("", false, false, !saveas.include_media);
4847 save_default_options ();
4849 if (saveas.copy_media && saveas.copy_external) {
4850 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4851 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4855 saveas.final_session_folder_name = _path;
4857 store_recent_sessions (_name, _path);
4859 if (!saveas.switch_to) {
4861 /* switch back to the way things were */
4865 set_snapshot_name (old_snapshot);
4867 (*_session_dir) = old_sd;
4873 if (internal_file_cnt) {
4874 /* reset these to their original values */
4875 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4876 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4881 /* prune session dirs, and update disk space statistics
4886 session_dirs.clear ();
4887 session_dirs.push_back (sp);
4888 refresh_disk_space ();
4890 /* ensure that all existing tracks reset their current capture source paths
4892 reset_write_sources (true, true);
4894 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4895 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4898 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4899 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4905 if (fs->within_session()) {
4906 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4907 fs->set_path (newpath);
4912 } catch (Glib::FileError& e) {
4914 saveas.failure_message = e.what();
4916 /* recursively remove all the directories */
4918 remove_directory (to_dir);
4926 saveas.failure_message = _("unknown reason");
4928 /* recursively remove all the directories */
4930 remove_directory (to_dir);
4940 static void set_progress (Progress* p, size_t n, size_t t)
4942 p->set_progress (float (n) / float(t));
4946 Session::archive_session (const std::string& dest,
4947 const std::string& name,
4948 ArchiveEncode compress_audio,
4949 bool only_used_sources,
4952 if (dest.empty () || name.empty ()) {
4956 /* save current values */
4957 bool was_dirty = dirty ();
4958 string old_path = _path;
4959 string old_name = _name;
4960 string old_snapshot = _current_snapshot_name;
4961 string old_sd = _session_dir->root_path();
4962 string old_config_search_path[DataType::num_types];
4963 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4964 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4966 /* ensure that session-path is included in search-path */
4968 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4969 if ((*sd).path == old_path) {
4977 /* create temporary dir to save session to */
4978 #ifdef PLATFORM_WINDOWS
4979 char tmp[256] = "C:\\TEMP\\";
4980 GetTempPath (sizeof (tmp), tmp);
4982 char const* tmp = getenv("TMPDIR");
4987 if ((strlen (tmp) + 21) > 1024) {
4992 strcpy (tmptpl, tmp);
4993 strcat (tmptpl, "ardourarchive-XXXXXX");
4994 char* tmpdir = g_mkdtemp (tmptpl);
5000 std::string to_dir = std::string (tmpdir);
5002 /* switch session directory temporarily */
5003 (*_session_dir) = to_dir;
5005 if (!_session_dir->create()) {
5006 (*_session_dir) = old_sd;
5007 remove_directory (to_dir);
5011 /* prepare archive */
5012 string archive = Glib::build_filename (dest, name + ".tar.xz");
5014 PBD::ScopedConnectionList progress_connection;
5015 PBD::FileArchive ar (archive);
5017 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5020 /* collect files to archive */
5021 std::map<string,string> filemap;
5023 vector<string> do_not_copy_extensions;
5024 do_not_copy_extensions.push_back (statefile_suffix);
5025 do_not_copy_extensions.push_back (pending_suffix);
5026 do_not_copy_extensions.push_back (backup_suffix);
5027 do_not_copy_extensions.push_back (temp_suffix);
5028 do_not_copy_extensions.push_back (history_suffix);
5030 vector<string> blacklist_dirs;
5031 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5032 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5033 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5034 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5035 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5036 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5038 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5040 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5041 if (only_used_sources) {
5042 playlists->sync_all_regions_with_regions ();
5043 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5046 // collect audio sources for this session, calc total size for encoding
5047 // add option to only include *used* sources (see Session::cleanup_sources)
5048 size_t total_size = 0;
5050 Glib::Threads::Mutex::Lock lm (source_lock);
5051 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5052 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5053 if (!afs || afs->readable_length () == 0) {
5057 if (only_used_sources) {
5061 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5066 std::string from = afs->path();
5068 if (compress_audio != NO_ENCODE) {
5069 total_size += afs->readable_length ();
5071 if (afs->within_session()) {
5072 filemap[from] = make_new_media_path (from, name, name);
5074 filemap[from] = make_new_media_path (from, name, name);
5075 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5082 if (compress_audio != NO_ENCODE) {
5084 progress->set_progress (2); // set to "encoding"
5085 progress->set_progress (0);
5088 Glib::Threads::Mutex::Lock lm (source_lock);
5089 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5090 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5091 if (!afs || afs->readable_length () == 0) {
5095 if (only_used_sources) {
5099 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5104 orig_sources[afs] = afs->path();
5106 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5107 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5108 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5111 progress->descend ((float)afs->readable_length () / total_size);
5115 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5116 afs->replace_file (new_path);
5119 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5123 progress->ascend ();
5129 progress->set_progress (-1); // set to "archiving"
5130 progress->set_progress (0);
5133 /* index files relevant for this session */
5134 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5135 vector<string> files;
5137 size_t prefix_len = (*sd).path.size();
5138 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5142 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5144 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5145 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5146 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5148 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5149 std::string from = *i;
5152 string filename = Glib::path_get_basename (from);
5153 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5154 if (filename == ".DS_STORE") {
5159 if (from.find (audiofile_dir_string) != string::npos) {
5161 } else if (from.find (midifile_dir_string) != string::npos) {
5162 filemap[from] = make_new_media_path (from, name, name);
5163 } else if (from.find (videofile_dir_string) != string::npos) {
5164 filemap[from] = make_new_media_path (from, name, name);
5166 bool do_copy = true;
5167 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5168 if (from.find (*v) != string::npos) {
5173 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5174 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5181 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5187 /* write session file */
5189 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5191 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5193 save_default_options ();
5195 size_t prefix_len = _path.size();
5196 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5200 /* collect session-state files */
5201 vector<string> files;
5202 do_not_copy_extensions.clear ();
5203 do_not_copy_extensions.push_back (history_suffix);
5205 blacklist_dirs.clear ();
5206 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5208 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5209 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5210 std::string from = *i;
5211 bool do_copy = true;
5212 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5213 if (from.find (*v) != string::npos) {
5218 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5219 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5225 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5229 /* restore original values */
5232 set_snapshot_name (old_snapshot);
5233 (*_session_dir) = old_sd;
5237 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5238 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5240 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5241 i->first->replace_file (i->second);
5244 int rv = ar.create (filemap);
5245 remove_directory (to_dir);
5251 Session::undo (uint32_t n)
5253 if (actively_recording()) {
5261 Session::redo (uint32_t n)
5263 if (actively_recording()) {