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));
273 _engine.MidiSelectionPortsChanged.connect_same_thread (*this, boost::bind (&Session::rewire_midi_selection_ports, this));
275 AudioDiskstream::allocate_working_buffers();
276 refresh_disk_space ();
278 /* we're finally ready to call set_state() ... all objects have
279 * been created, the engine is running.
283 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
284 error << _("Could not set session state from XML") << endmsg;
288 // set_state() will call setup_raid_path(), but if it's a new session we need
289 // to call setup_raid_path() here.
290 setup_raid_path (_path);
295 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
296 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
298 Config->map_parameters (ff);
299 config.map_parameters (ft);
300 _butler->map_parameters ();
302 /* Reset all panners */
304 Delivery::reset_panners ();
306 /* this will cause the CPM to instantiate any protocols that are in use
307 * (or mandatory), which will pass it this Session, and then call
308 * set_state() on each instantiated protocol to match stored state.
311 ControlProtocolManager::instance().set_session (this);
313 /* This must be done after the ControlProtocolManager set_session above,
314 as it will set states for ports which the ControlProtocolManager creates.
317 // XXX set state of MIDI::Port's
318 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
320 /* And this must be done after the MIDI::Manager::set_port_states as
321 * it will try to make connections whose details are loaded by set_port_states.
326 /* Let control protocols know that we are now all connected, so they
327 * could start talking to surfaces if they want to.
330 ControlProtocolManager::instance().midi_connectivity_established ();
332 if (_is_new && !no_auto_connect()) {
333 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
334 auto_connect_master_bus ();
337 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
339 /* update latencies */
341 initialize_latencies ();
343 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
344 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
345 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
347 } catch (AudioEngine::PortRegistrationFailure& err) {
348 /* handle this one in a different way than all others, so that its clear what happened */
349 error << err.what() << endmsg;
351 } catch (std::exception const & e) {
352 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
355 error << _("Unknown exception during session setup") << endmsg;
359 BootMessage (_("Reset Remote Controls"));
361 // send_full_time_code (0);
362 _engine.transport_locate (0);
364 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
365 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
367 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
370 /* initial program change will be delivered later; see ::config_changed() */
372 _state_of_the_state = Clean;
374 Port::set_connecting_blocked (false);
376 DirtyChanged (); /* EMIT SIGNAL */
380 } else if (state_was_pending) {
382 remove_pending_capture_state ();
383 state_was_pending = false;
386 /* Now, finally, we can fill the playback buffers */
388 BootMessage (_("Filling playback buffers"));
390 boost::shared_ptr<RouteList> rl = routes.reader();
391 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
392 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
393 if (trk && !trk->hidden()) {
394 trk->seek (_transport_frame, true);
402 Session::session_loaded ()
406 _state_of_the_state = Clean;
408 DirtyChanged (); /* EMIT SIGNAL */
412 } else if (state_was_pending) {
414 remove_pending_capture_state ();
415 state_was_pending = false;
418 /* Now, finally, we can fill the playback buffers */
420 BootMessage (_("Filling playback buffers"));
421 force_locate (_transport_frame, false);
425 Session::raid_path () const
427 Searchpath raid_search_path;
429 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
430 raid_search_path += (*i).path;
433 return raid_search_path.to_string ();
437 Session::setup_raid_path (string path)
446 session_dirs.clear ();
448 Searchpath search_path(path);
449 Searchpath sound_search_path;
450 Searchpath midi_search_path;
452 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
454 sp.blocks = 0; // not needed
455 session_dirs.push_back (sp);
457 SessionDirectory sdir(sp.path);
459 sound_search_path += sdir.sound_path ();
460 midi_search_path += sdir.midi_path ();
463 // reset the round-robin soundfile path thingie
464 last_rr_session_dir = session_dirs.begin();
468 Session::path_is_within_session (const std::string& path)
470 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
471 if (PBD::path_is_within (i->path, path)) {
479 Session::ensure_subdirs ()
483 dir = session_directory().peak_path();
485 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
486 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
490 dir = session_directory().sound_path();
492 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
493 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
497 dir = session_directory().midi_path();
499 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
500 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
504 dir = session_directory().dead_path();
506 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
507 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
511 dir = session_directory().export_path();
513 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
514 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
518 dir = analysis_dir ();
520 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
521 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
525 dir = plugins_dir ();
527 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
528 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
532 dir = externals_dir ();
534 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
535 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
542 /** @param session_template directory containing session template, or empty.
543 * Caller must not hold process lock.
546 Session::create (const string& session_template, BusProfile* bus_profile)
548 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
549 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
553 if (ensure_subdirs ()) {
557 _writable = exists_and_writable (_path);
559 if (!session_template.empty()) {
560 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
562 FILE* in = g_fopen (in_path.c_str(), "rb");
565 /* no need to call legalize_for_path() since the string
566 * in session_template is already a legal path name
568 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
570 FILE* out = g_fopen (out_path.c_str(), "wb");
574 stringstream new_session;
577 size_t charsRead = fread (buf, sizeof(char), 1024, in);
580 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
585 if (charsRead == 0) {
588 new_session.write (buf, charsRead);
592 string file_contents = new_session.str();
593 size_t writeSize = file_contents.length();
594 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
595 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
603 if (!ARDOUR::Profile->get_trx()) {
604 /* Copy plugin state files from template to new session */
605 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
606 copy_recurse (template_plugins, plugins_dir ());
612 error << string_compose (_("Could not open %1 for writing session template"), out_path)
619 error << string_compose (_("Could not open session template %1 for reading"), in_path)
626 if (Profile->get_trx()) {
628 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
629 Remember that this is a brand new session. Sessions
630 loaded from saved state will get this range from the saved state.
633 set_session_range_location (0, 0);
635 /* Initial loop location, from absolute zero, length 10 seconds */
637 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop, 0);
638 _locations->add (loc, true);
639 set_auto_loop_location (loc);
642 _state_of_the_state = Clean;
644 /* set up Master Out and Monitor Out if necessary */
649 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
651 // Waves Tracks: always create master bus for Tracks
652 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
653 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
661 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
662 r->input()->ensure_io (count, false, this);
663 r->output()->ensure_io (count, false, this);
669 /* prohibit auto-connect to master, because there isn't one */
670 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
674 add_routes (rl, false, false, false, PresentationInfo::max_order);
677 // Waves Tracks: Skip this. Always use autoconnection for Tracks
678 if (!ARDOUR::Profile->get_trx()) {
680 /* this allows the user to override settings with an environment variable.
683 if (no_auto_connect()) {
684 bus_profile->input_ac = AutoConnectOption (0);
685 bus_profile->output_ac = AutoConnectOption (0);
688 Config->set_input_auto_connect (bus_profile->input_ac);
689 Config->set_output_auto_connect (bus_profile->output_ac);
693 if (Config->get_use_monitor_bus() && bus_profile) {
694 add_monitor_section ();
701 Session::maybe_write_autosave()
703 if (dirty() && record_status() != Recording) {
704 save_state("", true);
709 Session::remove_pending_capture_state ()
711 std::string pending_state_file_path(_session_dir->root_path());
713 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
715 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
717 if (g_remove (pending_state_file_path.c_str()) != 0) {
718 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
719 pending_state_file_path, g_strerror (errno)) << endmsg;
723 /** Rename a state file.
724 * @param old_name Old snapshot name.
725 * @param new_name New snapshot name.
728 Session::rename_state (string old_name, string new_name)
730 if (old_name == _current_snapshot_name || old_name == _name) {
731 /* refuse to rename the current snapshot or the "main" one */
735 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
736 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
738 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
739 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
741 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
742 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
743 old_name, new_name, g_strerror(errno)) << endmsg;
747 /** Remove a state file.
748 * @param snapshot_name Snapshot name.
751 Session::remove_state (string snapshot_name)
753 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
754 // refuse to remove the current snapshot or the "main" one
758 std::string xml_path(_session_dir->root_path());
760 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
762 if (!create_backup_file (xml_path)) {
763 // don't remove it if a backup can't be made
764 // create_backup_file will log the error.
769 if (g_remove (xml_path.c_str()) != 0) {
770 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
771 xml_path, g_strerror (errno)) << endmsg;
775 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
777 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
779 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
782 std::string xml_path(_session_dir->root_path());
784 /* prevent concurrent saves from different threads */
786 Glib::Threads::Mutex::Lock lm (save_state_lock);
788 if (!_writable || (_state_of_the_state & CannotSave)) {
792 if (g_atomic_int_get(&_suspend_save)) {
796 _save_queued = false;
798 if (!_engine.connected ()) {
799 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
806 const int64_t save_start_time = g_get_monotonic_time();
809 /* tell sources we're saving first, in case they write out to a new file
810 * which should be saved with the state rather than the old one */
811 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
813 i->second->session_saved();
814 } catch (Evoral::SMF::FileError& e) {
815 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
819 SessionSaveUnderway (); /* EMIT SIGNAL */
821 bool mark_as_clean = true;
823 if (!snapshot_name.empty() && !switch_to_snapshot) {
824 mark_as_clean = false;
828 mark_as_clean = false;
829 tree.set_root (&get_template());
831 tree.set_root (&get_state());
834 if (snapshot_name.empty()) {
835 snapshot_name = _current_snapshot_name;
836 } else if (switch_to_snapshot) {
837 set_snapshot_name (snapshot_name);
840 assert (!snapshot_name.empty());
844 /* proper save: use statefile_suffix (.ardour in English) */
846 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
848 /* make a backup copy of the old file */
850 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
851 // create_backup_file will log the error
857 /* pending save: use pending_suffix (.pending in English) */
858 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
861 std::string tmp_path(_session_dir->root_path());
862 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
864 cerr << "actually writing state to " << tmp_path << endl;
866 if (!tree.write (tmp_path)) {
867 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
868 if (g_remove (tmp_path.c_str()) != 0) {
869 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
870 tmp_path, g_strerror (errno)) << endmsg;
876 cerr << "renaming state to " << xml_path << endl;
878 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
879 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
880 tmp_path, xml_path, g_strerror(errno)) << endmsg;
881 if (g_remove (tmp_path.c_str()) != 0) {
882 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
883 tmp_path, g_strerror (errno)) << endmsg;
891 save_history (snapshot_name);
894 bool was_dirty = dirty();
896 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
899 DirtyChanged (); /* EMIT SIGNAL */
903 StateSaved (snapshot_name); /* EMIT SIGNAL */
907 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
908 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
914 Session::restore_state (string snapshot_name)
916 if (load_state (snapshot_name) == 0) {
917 set_state (*state_tree->root(), Stateful::loading_state_version);
924 Session::load_state (string snapshot_name)
929 state_was_pending = false;
931 /* check for leftover pending state from a crashed capture attempt */
933 std::string xmlpath(_session_dir->root_path());
934 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
936 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
938 /* there is pending state from a crashed capture attempt */
940 boost::optional<int> r = AskAboutPendingState();
941 if (r.get_value_or (1)) {
942 state_was_pending = true;
946 if (!state_was_pending) {
947 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
950 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
951 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
952 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
953 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
958 state_tree = new XMLTree;
962 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
964 if (!state_tree->read (xmlpath)) {
965 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
971 XMLNode const & root (*state_tree->root());
973 if (root.name() != X_("Session")) {
974 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
980 XMLProperty const * prop;
982 if ((prop = root.property ("version")) == 0) {
983 /* no version implies very old version of Ardour */
984 Stateful::loading_state_version = 1000;
986 if (prop->value().find ('.') != string::npos) {
987 /* old school version format */
988 if (prop->value()[0] == '2') {
989 Stateful::loading_state_version = 2000;
991 Stateful::loading_state_version = 3000;
994 Stateful::loading_state_version = atoi (prop->value());
998 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
1000 std::string backup_path(_session_dir->root_path());
1001 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1002 backup_path = Glib::build_filename (backup_path, backup_filename);
1004 // only create a backup for a given statefile version once
1006 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1008 VersionMismatch (xmlpath, backup_path);
1010 if (!copy_file (xmlpath, backup_path)) {;
1016 save_snapshot_name (snapshot_name);
1022 Session::load_options (const XMLNode& node)
1025 config.set_variables (node);
1030 Session::save_default_options ()
1032 return config.save_state();
1036 Session::get_state()
1042 Session::get_template()
1044 /* if we don't disable rec-enable, diskstreams
1045 will believe they need to store their capture
1046 sources in their state node.
1049 disable_record (false);
1051 return state(false);
1055 Session::state (bool full_state)
1058 XMLNode* node = new XMLNode("Session");
1062 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1063 node->add_property("version", buf);
1065 child = node->add_child ("ProgramVersion");
1066 child->add_property("created-with", created_with);
1068 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1069 child->add_property("modified-with", modified_with);
1071 /* store configuration settings */
1075 node->add_property ("name", _name);
1076 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1077 node->add_property ("sample-rate", buf);
1079 if (session_dirs.size() > 1) {
1083 vector<space_and_path>::iterator i = session_dirs.begin();
1084 vector<space_and_path>::iterator next;
1086 ++i; /* skip the first one */
1090 while (i != session_dirs.end()) {
1094 if (next != session_dirs.end()) {
1095 p += G_SEARCHPATH_SEPARATOR;
1104 child = node->add_child ("Path");
1105 child->add_content (p);
1109 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1111 /* save the ID counter */
1113 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1114 node->add_property ("id-counter", buf);
1116 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1117 node->add_property ("name-counter", buf);
1119 /* save the event ID counter */
1121 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1122 node->add_property ("event-counter", buf);
1124 /* save the VCA counter */
1126 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1127 node->add_property ("vca-counter", buf);
1129 /* various options */
1131 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1132 if (!midi_port_nodes.empty()) {
1133 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1134 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1135 midi_port_stuff->add_child_nocopy (**n);
1137 node->add_child_nocopy (*midi_port_stuff);
1140 XMLNode& cfgxml (config.get_variables ());
1142 /* exclude search-paths from template */
1143 cfgxml.remove_nodes_and_delete ("name", "audio-search-path");
1144 cfgxml.remove_nodes_and_delete ("name", "midi-search-path");
1145 cfgxml.remove_nodes_and_delete ("name", "raid-path");
1147 node->add_child_nocopy (cfgxml);
1149 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1151 child = node->add_child ("Sources");
1154 Glib::Threads::Mutex::Lock sl (source_lock);
1156 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1158 /* Don't save information about non-file Sources, or
1159 * about non-destructive file sources that are empty
1160 * and unused by any regions.
1163 boost::shared_ptr<FileSource> fs;
1165 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1167 if (!fs->destructive()) {
1168 if (fs->empty() && !fs->used()) {
1173 child->add_child_nocopy (siter->second->get_state());
1178 child = node->add_child ("Regions");
1181 Glib::Threads::Mutex::Lock rl (region_lock);
1182 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1183 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1184 boost::shared_ptr<Region> r = i->second;
1185 /* only store regions not attached to playlists */
1186 if (r->playlist() == 0) {
1187 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1188 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1190 child->add_child_nocopy (r->get_state ());
1195 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1197 if (!cassocs.empty()) {
1198 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1200 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1202 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1203 i->first->id().print (buf, sizeof (buf));
1204 can->add_property (X_("copy"), buf);
1205 i->second->id().print (buf, sizeof (buf));
1206 can->add_property (X_("original"), buf);
1207 ca->add_child_nocopy (*can);
1217 node->add_child_nocopy (_locations->get_state());
1220 Locations loc (*this);
1221 // for a template, just create a new Locations, populate it
1222 // with the default start and end, and get the state for that.
1223 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange, 0);
1224 range->set (max_framepos, 0);
1226 XMLNode& locations_state = loc.get_state();
1228 if (ARDOUR::Profile->get_trx() && _locations) {
1229 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1230 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1231 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1232 locations_state.add_child_nocopy ((*i)->get_state ());
1236 node->add_child_nocopy (locations_state);
1239 child = node->add_child ("Bundles");
1241 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1242 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1243 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1245 child->add_child_nocopy (b->get_state());
1250 node->add_child_nocopy (_vca_manager->get_state());
1252 child = node->add_child ("Routes");
1254 boost::shared_ptr<RouteList> r = routes.reader ();
1256 RoutePublicOrderSorter cmp;
1257 RouteList public_order (*r);
1258 public_order.sort (cmp);
1260 /* the sort should have put the monitor out first */
1263 assert (_monitor_out == public_order.front());
1266 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1267 if (!(*i)->is_auditioner()) {
1269 child->add_child_nocopy ((*i)->get_state());
1271 child->add_child_nocopy ((*i)->get_template());
1277 playlists->add_state (node, full_state);
1279 child = node->add_child ("RouteGroups");
1280 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1281 child->add_child_nocopy ((*i)->get_state());
1285 XMLNode* gain_child = node->add_child ("Click");
1286 gain_child->add_child_nocopy (_click_io->state (full_state));
1287 gain_child->add_child_nocopy (_click_gain->state (full_state));
1291 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1292 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1296 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1297 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1300 node->add_child_nocopy (_speakers->get_state());
1301 node->add_child_nocopy (_tempo_map->get_state());
1302 node->add_child_nocopy (get_control_protocol_state());
1305 node->add_child_copy (*_extra_xml);
1309 Glib::Threads::Mutex::Lock lm (lua_lock);
1312 luabridge::LuaRef savedstate ((*_lua_save)());
1313 saved = savedstate.cast<std::string>();
1315 lua.collect_garbage ();
1318 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1319 std::string b64s (b64);
1322 XMLNode* script_node = new XMLNode (X_("Script"));
1323 script_node->add_property (X_("lua"), LUA_VERSION);
1324 script_node->add_content (b64s);
1325 node->add_child_nocopy (*script_node);
1332 Session::get_control_protocol_state ()
1334 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1335 return cpm.get_state();
1339 Session::set_state (const XMLNode& node, int version)
1344 XMLProperty const * prop;
1347 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1349 if (node.name() != X_("Session")) {
1350 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1354 if ((prop = node.property ("name")) != 0) {
1355 _name = prop->value ();
1358 if ((prop = node.property (X_("sample-rate"))) != 0) {
1360 _base_frame_rate = atoi (prop->value());
1361 _nominal_frame_rate = _base_frame_rate;
1363 assert (AudioEngine::instance()->running ());
1364 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1365 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1366 if (r.get_value_or (0)) {
1372 created_with = "unknown";
1373 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1374 if ((prop = child->property (X_("created-with"))) != 0) {
1375 created_with = prop->value ();
1379 setup_raid_path(_session_dir->root_path());
1381 if ((prop = node.property (X_("end-is-free"))) != 0) {
1382 _session_range_end_is_free = string_is_affirmative (prop->value());
1385 if ((prop = node.property (X_("id-counter"))) != 0) {
1387 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1388 ID::init_counter (x);
1390 /* old sessions used a timebased counter, so fake
1391 the startup ID counter based on a standard
1396 ID::init_counter (now);
1399 if ((prop = node.property (X_("name-counter"))) != 0) {
1400 init_name_id_counter (atoi (prop->value()));
1403 if ((prop = node.property (X_("event-counter"))) != 0) {
1404 Evoral::init_event_id_counter (atoi (prop->value()));
1407 if ((prop = node.property (X_("vca-counter"))) != 0) {
1409 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1410 VCA::set_next_vca_number (x);
1412 VCA::set_next_vca_number (1);
1415 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1416 _midi_ports->set_midi_port_states (child->children());
1419 IO::disable_connecting ();
1421 Stateful::save_extra_xml (node);
1423 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1424 load_options (*child);
1425 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1426 load_options (*child);
1428 error << _("Session: XML state has no options section") << endmsg;
1431 if (version >= 3000) {
1432 if ((child = find_named_node (node, "Metadata")) == 0) {
1433 warning << _("Session: XML state has no metadata section") << endmsg;
1434 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1439 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1440 _speakers->set_state (*child, version);
1443 if ((child = find_named_node (node, "Sources")) == 0) {
1444 error << _("Session: XML state has no sources section") << endmsg;
1446 } else if (load_sources (*child)) {
1450 if ((child = find_named_node (node, "TempoMap")) == 0) {
1451 error << _("Session: XML state has no Tempo Map section") << endmsg;
1453 } else if (_tempo_map->set_state (*child, version)) {
1457 if ((child = find_named_node (node, "Locations")) == 0) {
1458 error << _("Session: XML state has no locations section") << endmsg;
1460 } else if (_locations->set_state (*child, version)) {
1464 locations_changed ();
1466 if (_session_range_location) {
1467 AudioFileSource::set_header_position_offset (_session_range_location->start());
1470 if ((child = find_named_node (node, "Regions")) == 0) {
1471 error << _("Session: XML state has no Regions section") << endmsg;
1473 } else if (load_regions (*child)) {
1477 if ((child = find_named_node (node, "Playlists")) == 0) {
1478 error << _("Session: XML state has no playlists section") << endmsg;
1480 } else if (playlists->load (*this, *child)) {
1484 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1486 } else if (playlists->load_unused (*this, *child)) {
1490 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1491 if (load_compounds (*child)) {
1496 if (version >= 3000) {
1497 if ((child = find_named_node (node, "Bundles")) == 0) {
1498 warning << _("Session: XML state has no bundles section") << endmsg;
1501 /* We can't load Bundles yet as they need to be able
1502 to convert from port names to Port objects, which can't happen until
1504 _bundle_xml_node = new XMLNode (*child);
1508 if (version < 3000) {
1509 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1510 error << _("Session: XML state has no diskstreams section") << endmsg;
1512 } else if (load_diskstreams_2X (*child, version)) {
1517 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1518 _vca_manager->set_state (*child, version);
1521 if ((child = find_named_node (node, "Routes")) == 0) {
1522 error << _("Session: XML state has no routes section") << endmsg;
1524 } else if (load_routes (*child, version)) {
1528 /* Now that we have Routes and masters loaded, connect them if appropriate */
1530 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1532 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1533 _diskstreams_2X.clear ();
1535 if (version >= 3000) {
1537 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1538 error << _("Session: XML state has no route groups section") << endmsg;
1540 } else if (load_route_groups (*child, version)) {
1544 } else if (version < 3000) {
1546 if ((child = find_named_node (node, "EditGroups")) == 0) {
1547 error << _("Session: XML state has no edit groups section") << endmsg;
1549 } else if (load_route_groups (*child, version)) {
1553 if ((child = find_named_node (node, "MixGroups")) == 0) {
1554 error << _("Session: XML state has no mix groups section") << endmsg;
1556 } else if (load_route_groups (*child, version)) {
1561 if ((child = find_named_node (node, "Click")) == 0) {
1562 warning << _("Session: XML state has no click section") << endmsg;
1563 } else if (_click_io) {
1564 setup_click_state (&node);
1567 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1568 ControlProtocolManager::instance().set_state (*child, version);
1571 if ((child = find_named_node (node, "Script"))) {
1572 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1573 if (!(*n)->is_content ()) { continue; }
1575 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1577 Glib::Threads::Mutex::Lock lm (lua_lock);
1578 (*_lua_load)(std::string ((const char*)buf, size));
1579 } catch (luabridge::LuaException const& e) {
1580 cerr << "LuaException:" << e.what () << endl;
1586 update_route_record_state ();
1588 /* here beginneth the second phase ... */
1589 set_snapshot_name (_current_snapshot_name);
1591 StateReady (); /* EMIT SIGNAL */
1604 Session::load_routes (const XMLNode& node, int version)
1607 XMLNodeConstIterator niter;
1608 RouteList new_routes;
1610 nlist = node.children();
1614 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1616 boost::shared_ptr<Route> route;
1617 if (version < 3000) {
1618 route = XMLRouteFactory_2X (**niter, version);
1620 route = XMLRouteFactory (**niter, version);
1624 error << _("Session: cannot create Route from XML description.") << endmsg;
1628 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1630 new_routes.push_back (route);
1633 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1635 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1637 BootMessage (_("Finished adding tracks/busses"));
1642 boost::shared_ptr<Route>
1643 Session::XMLRouteFactory (const XMLNode& node, int version)
1645 boost::shared_ptr<Route> ret;
1647 if (node.name() != "Route") {
1651 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1653 DataType type = DataType::AUDIO;
1654 XMLProperty const * prop = node.property("default-type");
1657 type = DataType (prop->value());
1660 assert (type != DataType::NIL);
1664 boost::shared_ptr<Track> track;
1666 if (type == DataType::AUDIO) {
1667 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1669 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1672 if (track->init()) {
1676 if (track->set_state (node, version)) {
1680 BOOST_MARK_TRACK (track);
1684 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1685 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1687 if (r->init () == 0 && r->set_state (node, version) == 0) {
1688 BOOST_MARK_ROUTE (r);
1696 boost::shared_ptr<Route>
1697 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1699 boost::shared_ptr<Route> ret;
1701 if (node.name() != "Route") {
1705 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1707 ds_prop = node.property (X_("diskstream"));
1710 DataType type = DataType::AUDIO;
1711 XMLProperty const * prop = node.property("default-type");
1714 type = DataType (prop->value());
1717 assert (type != DataType::NIL);
1721 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1722 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1726 if (i == _diskstreams_2X.end()) {
1727 error << _("Could not find diskstream for route") << endmsg;
1728 return boost::shared_ptr<Route> ();
1731 boost::shared_ptr<Track> track;
1733 if (type == DataType::AUDIO) {
1734 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1736 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1739 if (track->init()) {
1743 if (track->set_state (node, version)) {
1747 track->set_diskstream (*i);
1749 BOOST_MARK_TRACK (track);
1753 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1754 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1756 if (r->init () == 0 && r->set_state (node, version) == 0) {
1757 BOOST_MARK_ROUTE (r);
1766 Session::load_regions (const XMLNode& node)
1769 XMLNodeConstIterator niter;
1770 boost::shared_ptr<Region> region;
1772 nlist = node.children();
1776 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1777 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1778 error << _("Session: cannot create Region from XML description.");
1779 XMLProperty const * name = (**niter).property("name");
1782 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1793 Session::load_compounds (const XMLNode& node)
1795 XMLNodeList calist = node.children();
1796 XMLNodeConstIterator caiter;
1797 XMLProperty const * caprop;
1799 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1800 XMLNode* ca = *caiter;
1804 if ((caprop = ca->property (X_("original"))) == 0) {
1807 orig_id = caprop->value();
1809 if ((caprop = ca->property (X_("copy"))) == 0) {
1812 copy_id = caprop->value();
1814 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1815 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1817 if (!orig || !copy) {
1818 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1824 RegionFactory::add_compound_association (orig, copy);
1831 Session::load_nested_sources (const XMLNode& node)
1834 XMLNodeConstIterator niter;
1836 nlist = node.children();
1838 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1839 if ((*niter)->name() == "Source") {
1841 /* it may already exist, so don't recreate it unnecessarily
1844 XMLProperty const * prop = (*niter)->property (X_("id"));
1846 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1850 ID source_id (prop->value());
1852 if (!source_by_id (source_id)) {
1855 SourceFactory::create (*this, **niter, true);
1857 catch (failed_constructor& err) {
1858 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1865 boost::shared_ptr<Region>
1866 Session::XMLRegionFactory (const XMLNode& node, bool full)
1868 XMLProperty const * type = node.property("type");
1872 const XMLNodeList& nlist = node.children();
1874 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1875 XMLNode *child = (*niter);
1876 if (child->name() == "NestedSource") {
1877 load_nested_sources (*child);
1881 if (!type || type->value() == "audio") {
1882 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1883 } else if (type->value() == "midi") {
1884 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1887 } catch (failed_constructor& err) {
1888 return boost::shared_ptr<Region> ();
1891 return boost::shared_ptr<Region> ();
1894 boost::shared_ptr<AudioRegion>
1895 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1897 XMLProperty const * prop;
1898 boost::shared_ptr<Source> source;
1899 boost::shared_ptr<AudioSource> as;
1901 SourceList master_sources;
1902 uint32_t nchans = 1;
1905 if (node.name() != X_("Region")) {
1906 return boost::shared_ptr<AudioRegion>();
1909 if ((prop = node.property (X_("channels"))) != 0) {
1910 nchans = atoi (prop->value().c_str());
1913 if ((prop = node.property ("name")) == 0) {
1914 cerr << "no name for this region\n";
1918 if ((prop = node.property (X_("source-0"))) == 0) {
1919 if ((prop = node.property ("source")) == 0) {
1920 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1921 return boost::shared_ptr<AudioRegion>();
1925 PBD::ID s_id (prop->value());
1927 if ((source = source_by_id (s_id)) == 0) {
1928 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1929 return boost::shared_ptr<AudioRegion>();
1932 as = boost::dynamic_pointer_cast<AudioSource>(source);
1934 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1935 return boost::shared_ptr<AudioRegion>();
1938 sources.push_back (as);
1940 /* pickup other channels */
1942 for (uint32_t n=1; n < nchans; ++n) {
1943 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1944 if ((prop = node.property (buf)) != 0) {
1946 PBD::ID id2 (prop->value());
1948 if ((source = source_by_id (id2)) == 0) {
1949 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1950 return boost::shared_ptr<AudioRegion>();
1953 as = boost::dynamic_pointer_cast<AudioSource>(source);
1955 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1956 return boost::shared_ptr<AudioRegion>();
1958 sources.push_back (as);
1962 for (uint32_t n = 0; n < nchans; ++n) {
1963 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1964 if ((prop = node.property (buf)) != 0) {
1966 PBD::ID id2 (prop->value());
1968 if ((source = source_by_id (id2)) == 0) {
1969 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1970 return boost::shared_ptr<AudioRegion>();
1973 as = boost::dynamic_pointer_cast<AudioSource>(source);
1975 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1976 return boost::shared_ptr<AudioRegion>();
1978 master_sources.push_back (as);
1983 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1985 /* a final detail: this is the one and only place that we know how long missing files are */
1987 if (region->whole_file()) {
1988 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1989 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1991 sfp->set_length (region->length());
1996 if (!master_sources.empty()) {
1997 if (master_sources.size() != nchans) {
1998 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
2000 region->set_master_sources (master_sources);
2008 catch (failed_constructor& err) {
2009 return boost::shared_ptr<AudioRegion>();
2013 boost::shared_ptr<MidiRegion>
2014 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2016 XMLProperty const * prop;
2017 boost::shared_ptr<Source> source;
2018 boost::shared_ptr<MidiSource> ms;
2021 if (node.name() != X_("Region")) {
2022 return boost::shared_ptr<MidiRegion>();
2025 if ((prop = node.property ("name")) == 0) {
2026 cerr << "no name for this region\n";
2030 if ((prop = node.property (X_("source-0"))) == 0) {
2031 if ((prop = node.property ("source")) == 0) {
2032 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2033 return boost::shared_ptr<MidiRegion>();
2037 PBD::ID s_id (prop->value());
2039 if ((source = source_by_id (s_id)) == 0) {
2040 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2041 return boost::shared_ptr<MidiRegion>();
2044 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2046 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2047 return boost::shared_ptr<MidiRegion>();
2050 sources.push_back (ms);
2053 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2054 /* a final detail: this is the one and only place that we know how long missing files are */
2056 if (region->whole_file()) {
2057 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2058 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2060 sfp->set_length (region->length());
2068 catch (failed_constructor& err) {
2069 return boost::shared_ptr<MidiRegion>();
2074 Session::get_sources_as_xml ()
2077 XMLNode* node = new XMLNode (X_("Sources"));
2078 Glib::Threads::Mutex::Lock lm (source_lock);
2080 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2081 node->add_child_nocopy (i->second->get_state());
2088 Session::reset_write_sources (bool mark_write_complete, bool force)
2090 boost::shared_ptr<RouteList> rl = routes.reader();
2091 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2092 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2094 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2095 tr->reset_write_sources(mark_write_complete, force);
2096 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2102 Session::load_sources (const XMLNode& node)
2105 XMLNodeConstIterator niter;
2106 boost::shared_ptr<Source> source; /* don't need this but it stops some
2107 * versions of gcc complaining about
2108 * discarded return values.
2111 nlist = node.children();
2115 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2116 #ifdef PLATFORM_WINDOWS
2122 #ifdef PLATFORM_WINDOWS
2123 // do not show "insert media" popups (files embedded from removable media).
2124 old_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
2126 if ((source = XMLSourceFactory (**niter)) == 0) {
2127 error << _("Session: cannot create Source from XML description.") << endmsg;
2129 #ifdef PLATFORM_WINDOWS
2130 SetErrorMode(old_mode);
2133 } catch (MissingSource& err) {
2134 #ifdef PLATFORM_WINDOWS
2135 SetErrorMode(old_mode);
2140 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2141 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2142 PROGRAM_NAME) << endmsg;
2146 if (!no_questions_about_missing_files) {
2147 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2152 switch (user_choice) {
2154 /* user added a new search location, so try again */
2159 /* user asked to quit the entire session load
2164 no_questions_about_missing_files = true;
2168 no_questions_about_missing_files = true;
2175 case DataType::AUDIO:
2176 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2179 case DataType::MIDI:
2180 /* The MIDI file is actually missing so
2181 * just create a new one in the same
2182 * location. Do not announce its
2186 if (!Glib::path_is_absolute (err.path)) {
2187 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2189 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2194 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2195 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2196 /* reset ID to match the missing one */
2197 source->set_id (**niter);
2198 /* Now we can announce it */
2199 SourceFactory::SourceCreated (source);
2210 boost::shared_ptr<Source>
2211 Session::XMLSourceFactory (const XMLNode& node)
2213 if (node.name() != "Source") {
2214 return boost::shared_ptr<Source>();
2218 /* note: do peak building in another thread when loading session state */
2219 return SourceFactory::create (*this, node, true);
2222 catch (failed_constructor& err) {
2223 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2224 return boost::shared_ptr<Source>();
2229 Session::save_template (string template_name, bool replace_existing)
2231 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2235 bool absolute_path = Glib::path_is_absolute (template_name);
2237 /* directory to put the template in */
2238 std::string template_dir_path;
2240 if (!absolute_path) {
2241 std::string user_template_dir(user_template_directory());
2243 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2244 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2245 user_template_dir, g_strerror (errno)) << endmsg;
2249 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2251 template_dir_path = template_name;
2254 if (!ARDOUR::Profile->get_trx()) {
2255 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2256 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2257 template_dir_path) << endmsg;
2261 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2262 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2263 template_dir_path, g_strerror (errno)) << endmsg;
2269 std::string template_file_path;
2271 if (ARDOUR::Profile->get_trx()) {
2272 template_file_path = template_name;
2274 if (absolute_path) {
2275 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2277 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2281 SessionSaveUnderway (); /* EMIT SIGNAL */
2286 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2287 tree.set_root (&get_template());
2290 if (!tree.write (template_file_path)) {
2291 error << _("template not saved") << endmsg;
2295 store_recent_templates (template_file_path);
2301 Session::refresh_disk_space ()
2303 #if __APPLE__ || __FreeBSD__ || __NetBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2305 Glib::Threads::Mutex::Lock lm (space_lock);
2307 /* get freespace on every FS that is part of the session path */
2309 _total_free_4k_blocks = 0;
2310 _total_free_4k_blocks_uncertain = false;
2312 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2313 #if defined(__NetBSD__)
2314 struct statvfs statfsbuf;
2316 statvfs (i->path.c_str(), &statfsbuf);
2318 struct statfs statfsbuf;
2320 statfs (i->path.c_str(), &statfsbuf);
2322 double const scale = statfsbuf.f_bsize / 4096.0;
2324 /* See if this filesystem is read-only */
2325 struct statvfs statvfsbuf;
2326 statvfs (i->path.c_str(), &statvfsbuf);
2328 /* f_bavail can be 0 if it is undefined for whatever
2329 filesystem we are looking at; Samba shares mounted
2330 via GVFS are an example of this.
2332 if (statfsbuf.f_bavail == 0) {
2333 /* block count unknown */
2335 i->blocks_unknown = true;
2336 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2337 /* read-only filesystem */
2339 i->blocks_unknown = false;
2341 /* read/write filesystem with known space */
2342 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2343 i->blocks_unknown = false;
2346 _total_free_4k_blocks += i->blocks;
2347 if (i->blocks_unknown) {
2348 _total_free_4k_blocks_uncertain = true;
2351 #elif defined PLATFORM_WINDOWS
2352 vector<string> scanned_volumes;
2353 vector<string>::iterator j;
2354 vector<space_and_path>::iterator i;
2355 DWORD nSectorsPerCluster, nBytesPerSector,
2356 nFreeClusters, nTotalClusters;
2360 _total_free_4k_blocks = 0;
2362 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2363 strncpy (disk_drive, (*i).path.c_str(), 3);
2367 volume_found = false;
2368 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2370 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2371 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2372 i->blocks = (uint32_t)(nFreeBytes / 4096);
2374 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2375 if (0 == j->compare(disk_drive)) {
2376 volume_found = true;
2381 if (!volume_found) {
2382 scanned_volumes.push_back(disk_drive);
2383 _total_free_4k_blocks += i->blocks;
2388 if (0 == _total_free_4k_blocks) {
2389 strncpy (disk_drive, path().c_str(), 3);
2392 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2394 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2395 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2396 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2403 Session::get_best_session_directory_for_new_audio ()
2405 vector<space_and_path>::iterator i;
2406 string result = _session_dir->root_path();
2408 /* handle common case without system calls */
2410 if (session_dirs.size() == 1) {
2414 /* OK, here's the algorithm we're following here:
2416 We want to select which directory to use for
2417 the next file source to be created. Ideally,
2418 we'd like to use a round-robin process so as to
2419 get maximum performance benefits from splitting
2420 the files across multiple disks.
2422 However, in situations without much diskspace, an
2423 RR approach may end up filling up a filesystem
2424 with new files while others still have space.
2425 Its therefore important to pay some attention to
2426 the freespace in the filesystem holding each
2427 directory as well. However, if we did that by
2428 itself, we'd keep creating new files in the file
2429 system with the most space until it was as full
2430 as all others, thus negating any performance
2431 benefits of this RAID-1 like approach.
2433 So, we use a user-configurable space threshold. If
2434 there are at least 2 filesystems with more than this
2435 much space available, we use RR selection between them.
2436 If not, then we pick the filesystem with the most space.
2438 This gets a good balance between the two
2442 refresh_disk_space ();
2444 int free_enough = 0;
2446 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2447 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2452 if (free_enough >= 2) {
2453 /* use RR selection process, ensuring that the one
2457 i = last_rr_session_dir;
2460 if (++i == session_dirs.end()) {
2461 i = session_dirs.begin();
2464 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2465 SessionDirectory sdir(i->path);
2466 if (sdir.create ()) {
2468 last_rr_session_dir = i;
2473 } while (i != last_rr_session_dir);
2477 /* pick FS with the most freespace (and that
2478 seems to actually work ...)
2481 vector<space_and_path> sorted;
2482 space_and_path_ascending_cmp cmp;
2484 sorted = session_dirs;
2485 sort (sorted.begin(), sorted.end(), cmp);
2487 for (i = sorted.begin(); i != sorted.end(); ++i) {
2488 SessionDirectory sdir(i->path);
2489 if (sdir.create ()) {
2491 last_rr_session_dir = i;
2501 Session::automation_dir () const
2503 return Glib::build_filename (_path, automation_dir_name);
2507 Session::analysis_dir () const
2509 return Glib::build_filename (_path, analysis_dir_name);
2513 Session::plugins_dir () const
2515 return Glib::build_filename (_path, plugins_dir_name);
2519 Session::externals_dir () const
2521 return Glib::build_filename (_path, externals_dir_name);
2525 Session::load_bundles (XMLNode const & node)
2527 XMLNodeList nlist = node.children();
2528 XMLNodeConstIterator niter;
2532 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2533 if ((*niter)->name() == "InputBundle") {
2534 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2535 } else if ((*niter)->name() == "OutputBundle") {
2536 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2538 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2547 Session::load_route_groups (const XMLNode& node, int version)
2549 XMLNodeList nlist = node.children();
2550 XMLNodeConstIterator niter;
2554 if (version >= 3000) {
2556 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2557 if ((*niter)->name() == "RouteGroup") {
2558 RouteGroup* rg = new RouteGroup (*this, "");
2559 add_route_group (rg);
2560 rg->set_state (**niter, version);
2564 } else if (version < 3000) {
2566 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2567 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2568 RouteGroup* rg = new RouteGroup (*this, "");
2569 add_route_group (rg);
2570 rg->set_state (**niter, version);
2579 state_file_filter (const string &str, void* /*arg*/)
2581 return (str.length() > strlen(statefile_suffix) &&
2582 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2586 remove_end(string state)
2588 string statename(state);
2590 string::size_type start,end;
2591 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2592 statename = statename.substr (start+1);
2595 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2596 end = statename.length();
2599 return string(statename.substr (0, end));
2603 Session::possible_states (string path)
2605 vector<string> states;
2606 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2608 transform(states.begin(), states.end(), states.begin(), remove_end);
2610 sort (states.begin(), states.end());
2616 Session::possible_states () const
2618 return possible_states(_path);
2622 Session::new_route_group (const std::string& name)
2624 RouteGroup* rg = NULL;
2626 for (std::list<RouteGroup*>::const_iterator i = _route_groups.begin (); i != _route_groups.end (); ++i) {
2627 if ((*i)->name () == name) {
2634 rg = new RouteGroup (*this, name);
2635 add_route_group (rg);
2641 Session::add_route_group (RouteGroup* g)
2643 _route_groups.push_back (g);
2644 route_group_added (g); /* EMIT SIGNAL */
2646 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2647 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2648 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2654 Session::remove_route_group (RouteGroup& rg)
2656 list<RouteGroup*>::iterator i;
2658 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2659 _route_groups.erase (i);
2662 route_group_removed (); /* EMIT SIGNAL */
2666 /** Set a new order for our route groups, without adding or removing any.
2667 * @param groups Route group list in the new order.
2670 Session::reorder_route_groups (list<RouteGroup*> groups)
2672 _route_groups = groups;
2674 route_groups_reordered (); /* EMIT SIGNAL */
2680 Session::route_group_by_name (string name)
2682 list<RouteGroup *>::iterator i;
2684 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2685 if ((*i)->name() == name) {
2693 Session::all_route_group() const
2695 return *_all_route_group;
2699 Session::add_commands (vector<Command*> const & cmds)
2701 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2707 Session::add_command (Command* const cmd)
2709 assert (_current_trans);
2710 DEBUG_UNDO_HISTORY (
2711 string_compose ("Current Undo Transaction %1, adding command: %2",
2712 _current_trans->name (),
2714 _current_trans->add_command (cmd);
2717 PBD::StatefulDiffCommand*
2718 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2720 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2726 Session::begin_reversible_command (const string& name)
2728 begin_reversible_command (g_quark_from_string (name.c_str ()));
2731 /** Begin a reversible command using a GQuark to identify it.
2732 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2733 * but there must be as many begin...()s as there are commit...()s.
2736 Session::begin_reversible_command (GQuark q)
2738 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2739 to hold all the commands that are committed. This keeps the order of
2740 commands correct in the history.
2743 if (_current_trans == 0) {
2744 DEBUG_UNDO_HISTORY (string_compose (
2745 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2747 /* start a new transaction */
2748 assert (_current_trans_quarks.empty ());
2749 _current_trans = new UndoTransaction();
2750 _current_trans->set_name (g_quark_to_string (q));
2752 DEBUG_UNDO_HISTORY (
2753 string_compose ("Begin Reversible Command, current transaction: %1",
2754 _current_trans->name ()));
2757 _current_trans_quarks.push_front (q);
2761 Session::abort_reversible_command ()
2763 if (_current_trans != 0) {
2764 DEBUG_UNDO_HISTORY (
2765 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2766 _current_trans->clear();
2767 delete _current_trans;
2769 _current_trans_quarks.clear();
2774 Session::commit_reversible_command (Command *cmd)
2776 assert (_current_trans);
2777 assert (!_current_trans_quarks.empty ());
2782 DEBUG_UNDO_HISTORY (
2783 string_compose ("Current Undo Transaction %1, adding command: %2",
2784 _current_trans->name (),
2786 _current_trans->add_command (cmd);
2789 DEBUG_UNDO_HISTORY (
2790 string_compose ("Commit Reversible Command, current transaction: %1",
2791 _current_trans->name ()));
2793 _current_trans_quarks.pop_front ();
2795 if (!_current_trans_quarks.empty ()) {
2796 DEBUG_UNDO_HISTORY (
2797 string_compose ("Commit Reversible Command, transaction is not "
2798 "top-level, current transaction: %1",
2799 _current_trans->name ()));
2800 /* the transaction we're committing is not the top-level one */
2804 if (_current_trans->empty()) {
2805 /* no commands were added to the transaction, so just get rid of it */
2806 DEBUG_UNDO_HISTORY (
2807 string_compose ("Commit Reversible Command, No commands were "
2808 "added to current transaction: %1",
2809 _current_trans->name ()));
2810 delete _current_trans;
2815 gettimeofday (&now, 0);
2816 _current_trans->set_timestamp (now);
2818 _history.add (_current_trans);
2823 accept_all_audio_files (const string& path, void* /*arg*/)
2825 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2829 if (!AudioFileSource::safe_audio_file_extension (path)) {
2837 accept_all_midi_files (const string& path, void* /*arg*/)
2839 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2843 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2844 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2845 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2849 accept_all_state_files (const string& path, void* /*arg*/)
2851 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2855 std::string const statefile_ext (statefile_suffix);
2856 if (path.length() >= statefile_ext.length()) {
2857 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2864 Session::find_all_sources (string path, set<string>& result)
2869 if (!tree.read (path)) {
2873 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2878 XMLNodeConstIterator niter;
2880 nlist = node->children();
2884 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2886 XMLProperty const * prop;
2888 if ((prop = (*niter)->property (X_("type"))) == 0) {
2892 DataType type (prop->value());
2894 if ((prop = (*niter)->property (X_("name"))) == 0) {
2898 if (Glib::path_is_absolute (prop->value())) {
2899 /* external file, ignore */
2907 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2908 result.insert (found_path);
2916 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2918 vector<string> state_files;
2920 string this_snapshot_path;
2926 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2927 ripped = ripped.substr (0, ripped.length() - 1);
2930 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2932 if (state_files.empty()) {
2937 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2938 this_snapshot_path += statefile_suffix;
2940 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2942 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2944 if (exclude_this_snapshot && *i == this_snapshot_path) {
2945 cerr << "\texcluded\n";
2950 if (find_all_sources (*i, result) < 0) {
2958 struct RegionCounter {
2959 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2960 AudioSourceList::iterator iter;
2961 boost::shared_ptr<Region> region;
2964 RegionCounter() : count (0) {}
2968 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2970 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2971 return r.get_value_or (1);
2975 Session::cleanup_regions ()
2977 bool removed = false;
2978 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2980 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2982 uint32_t used = playlists->region_use_count (i->second);
2984 if (used == 0 && !i->second->automatic ()) {
2985 boost::weak_ptr<Region> w = i->second;
2988 RegionFactory::map_remove (w);
2995 // re-check to remove parent references of compound regions
2996 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2997 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
3001 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
3002 if (0 == playlists->region_use_count (i->second)) {
3003 boost::weak_ptr<Region> w = i->second;
3005 RegionFactory::map_remove (w);
3012 /* dump the history list */
3019 Session::can_cleanup_peakfiles () const
3021 if (deletion_in_progress()) {
3024 if (!_writable || (_state_of_the_state & CannotSave)) {
3025 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3028 if (record_status() == Recording) {
3029 error << _("Cannot cleanup peak-files while recording") << endmsg;
3036 Session::cleanup_peakfiles ()
3038 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3043 assert (can_cleanup_peakfiles ());
3044 assert (!peaks_cleanup_in_progres());
3046 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3048 int timeout = 5000; // 5 seconds
3049 while (!SourceFactory::files_with_peaks.empty()) {
3050 Glib::usleep (1000);
3051 if (--timeout < 0) {
3052 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3053 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3058 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3059 boost::shared_ptr<AudioSource> as;
3060 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3061 as->close_peakfile();
3065 PBD::clear_directory (session_directory().peak_path());
3067 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3069 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3070 boost::shared_ptr<AudioSource> as;
3071 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3072 SourceFactory::setup_peakfile(as, true);
3079 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3081 pl->deep_sources (*all_sources);
3085 Session::cleanup_sources (CleanupReport& rep)
3087 // FIXME: needs adaptation to midi
3089 vector<boost::shared_ptr<Source> > dead_sources;
3092 vector<string> candidates;
3093 vector<string> unused;
3094 set<string> sources_used_by_all_snapshots;
3101 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3103 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3105 /* this is mostly for windows which doesn't allow file
3106 * renaming if the file is in use. But we don't special
3107 * case it because we need to know if this causes
3108 * problems, and the easiest way to notice that is to
3109 * keep it in place for all platforms.
3112 request_stop (false);
3114 _butler->wait_until_finished ();
3116 /* consider deleting all unused playlists */
3118 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3123 /* sync the "all regions" property of each playlist with its current state
3126 playlists->sync_all_regions_with_regions ();
3128 /* find all un-used sources */
3133 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3135 SourceMap::iterator tmp;
3140 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3144 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3145 dead_sources.push_back (i->second);
3146 i->second->drop_references ();
3152 /* build a list of all the possible audio directories for the session */
3154 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3155 SessionDirectory sdir ((*i).path);
3156 asp += sdir.sound_path();
3158 audio_path += asp.to_string();
3161 /* build a list of all the possible midi directories for the session */
3163 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3164 SessionDirectory sdir ((*i).path);
3165 msp += sdir.midi_path();
3167 midi_path += msp.to_string();
3169 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3170 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3172 /* add sources from all other snapshots as "used", but don't use this
3173 snapshot because the state file on disk still references sources we
3174 may have already dropped.
3177 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3179 /* Although the region factory has a list of all regions ever created
3180 * for this session, we're only interested in regions actually in
3181 * playlists right now. So merge all playlist regions lists together.
3183 * This will include the playlists used within compound regions.
3186 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3188 /* add our current source list
3191 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3192 boost::shared_ptr<FileSource> fs;
3193 SourceMap::iterator tmp = i;
3196 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3202 /* this is mostly for windows which doesn't allow file
3203 * renaming if the file is in use. But we do not special
3204 * case it because we need to know if this causes
3205 * problems, and the easiest way to notice that is to
3206 * keep it in place for all platforms.
3211 if (!fs->is_stub()) {
3213 /* Note that we're checking a list of all
3214 * sources across all snapshots with the list
3215 * of sources used by this snapshot.
3218 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3219 /* this source is in use by this snapshot */
3220 sources_used_by_all_snapshots.insert (fs->path());
3221 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3223 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3224 /* this source is NOT in use by this snapshot
3227 /* remove all related regions from RegionFactory master list
3230 RegionFactory::remove_regions_using_source (i->second);
3232 /* remove from our current source list
3233 * also. We may not remove it from
3234 * disk, because it may be used by
3235 * other snapshots, but it isn't used inside this
3236 * snapshot anymore, so we don't need a
3247 /* now check each candidate source to see if it exists in the list of
3248 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3251 cerr << "Candidates: " << candidates.size() << endl;
3252 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3254 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3259 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3261 tmppath1 = canonical_path (spath);
3262 tmppath2 = canonical_path ((*i));
3264 cerr << "\t => " << tmppath2 << endl;
3266 if (tmppath1 == tmppath2) {
3273 unused.push_back (spath);
3277 cerr << "Actually unused: " << unused.size() << endl;
3279 if (unused.empty()) {
3285 /* now try to move all unused files into the "dead" directory(ies) */
3287 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3292 /* don't move the file across filesystems, just
3293 stick it in the `dead_dir_name' directory
3294 on whichever filesystem it was already on.
3297 if ((*x).find ("/sounds/") != string::npos) {
3299 /* old school, go up 1 level */
3301 newpath = Glib::path_get_dirname (*x); // "sounds"
3302 newpath = Glib::path_get_dirname (newpath); // "session-name"
3306 /* new school, go up 4 levels */
3308 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3309 newpath = Glib::path_get_dirname (newpath); // "session-name"
3310 newpath = Glib::path_get_dirname (newpath); // "interchange"
3311 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3314 newpath = Glib::build_filename (newpath, dead_dir_name);
3316 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3317 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3321 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3323 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3325 /* the new path already exists, try versioning */
3327 char buf[PATH_MAX+1];
3331 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3334 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3335 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3339 if (version == 999) {
3340 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3344 newpath = newpath_v;
3349 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3350 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3351 newpath, g_strerror (errno)) << endmsg;
3355 /* see if there an easy to find peakfile for this file, and remove it.
3358 string base = Glib::path_get_basename (*x);
3359 base += "%A"; /* this is what we add for the channel suffix of all native files,
3360 or for the first channel of embedded files. it will miss
3361 some peakfiles for other channels
3363 string peakpath = construct_peak_filepath (base);
3365 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3366 if (::g_unlink (peakpath.c_str ()) != 0) {
3367 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3368 g_strerror (errno)) << endmsg;
3369 /* try to back out */
3370 ::g_rename (newpath.c_str (), _path.c_str ());
3375 rep.paths.push_back (*x);
3376 rep.space += statbuf.st_size;
3379 /* dump the history list */
3383 /* save state so we don't end up a session file
3384 referring to non-existent sources.
3391 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3397 Session::cleanup_trash_sources (CleanupReport& rep)
3399 // FIXME: needs adaptation for MIDI
3401 vector<space_and_path>::iterator i;
3407 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3409 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3411 clear_directory (dead_dir, &rep.space, &rep.paths);
3418 Session::set_dirty ()
3420 /* never mark session dirty during loading */
3422 if (_state_of_the_state & Loading) {
3426 bool was_dirty = dirty();
3428 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3432 DirtyChanged(); /* EMIT SIGNAL */
3438 Session::set_clean ()
3440 bool was_dirty = dirty();
3442 _state_of_the_state = Clean;
3446 DirtyChanged(); /* EMIT SIGNAL */
3451 Session::set_deletion_in_progress ()
3453 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3457 Session::clear_deletion_in_progress ()
3459 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3463 Session::add_controllable (boost::shared_ptr<Controllable> c)
3465 /* this adds a controllable to the list managed by the Session.
3466 this is a subset of those managed by the Controllable class
3467 itself, and represents the only ones whose state will be saved
3468 as part of the session.
3471 Glib::Threads::Mutex::Lock lm (controllables_lock);
3472 controllables.insert (c);
3475 struct null_deleter { void operator()(void const *) const {} };
3478 Session::remove_controllable (Controllable* c)
3480 if (_state_of_the_state & Deletion) {
3484 Glib::Threads::Mutex::Lock lm (controllables_lock);
3486 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3488 if (x != controllables.end()) {
3489 controllables.erase (x);
3493 boost::shared_ptr<Controllable>
3494 Session::controllable_by_id (const PBD::ID& id)
3496 Glib::Threads::Mutex::Lock lm (controllables_lock);
3498 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3499 if ((*i)->id() == id) {
3504 return boost::shared_ptr<Controllable>();
3507 boost::shared_ptr<Controllable>
3508 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3510 boost::shared_ptr<Controllable> c;
3511 boost::shared_ptr<Stripable> s;
3512 boost::shared_ptr<Route> r;
3514 switch (desc.top_level_type()) {
3515 case ControllableDescriptor::NamedRoute:
3517 std::string str = desc.top_level_name();
3519 if (str == "Master" || str == "master") {
3521 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3523 } else if (str == "auditioner") {
3526 s = route_by_name (desc.top_level_name());
3532 case ControllableDescriptor::PresentationOrderRoute:
3533 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3536 case ControllableDescriptor::PresentationOrderTrack:
3537 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3540 case ControllableDescriptor::PresentationOrderBus:
3541 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3544 case ControllableDescriptor::PresentationOrderVCA:
3545 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3548 case ControllableDescriptor::SelectionCount:
3549 s = route_by_selected_count (desc.selection_id());
3557 r = boost::dynamic_pointer_cast<Route> (s);
3559 switch (desc.subtype()) {
3560 case ControllableDescriptor::Gain:
3561 c = s->gain_control ();
3564 case ControllableDescriptor::Trim:
3565 c = s->trim_control ();
3568 case ControllableDescriptor::Solo:
3569 c = s->solo_control();
3572 case ControllableDescriptor::Mute:
3573 c = s->mute_control();
3576 case ControllableDescriptor::Recenable:
3577 c = s->rec_enable_control ();
3580 case ControllableDescriptor::PanDirection:
3581 c = s->pan_azimuth_control();
3584 case ControllableDescriptor::PanWidth:
3585 c = s->pan_width_control();
3588 case ControllableDescriptor::PanElevation:
3589 c = s->pan_elevation_control();
3592 case ControllableDescriptor::Balance:
3593 /* XXX simple pan control */
3596 case ControllableDescriptor::PluginParameter:
3598 uint32_t plugin = desc.target (0);
3599 uint32_t parameter_index = desc.target (1);
3601 /* revert to zero based counting */
3607 if (parameter_index > 0) {
3615 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3618 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3619 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3624 case ControllableDescriptor::SendGain: {
3625 uint32_t send = desc.target (0);
3632 c = r->send_level_controllable (send);
3637 /* relax and return a null pointer */
3645 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3648 Stateful::add_instant_xml (node, _path);
3651 if (write_to_config) {
3652 Config->add_instant_xml (node);
3657 Session::instant_xml (const string& node_name)
3659 #ifdef MIXBUS // "Safe Mode" (shift + click open) -> also ignore instant.xml
3660 if (get_disable_all_loaded_plugins ()) {
3664 return Stateful::instant_xml (node_name, _path);
3668 Session::save_history (string snapshot_name)
3676 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3677 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3681 if (snapshot_name.empty()) {
3682 snapshot_name = _current_snapshot_name;
3685 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3686 const string backup_filename = history_filename + backup_suffix;
3687 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3688 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3690 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3691 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3692 error << _("could not backup old history file, current history not saved") << endmsg;
3697 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3699 if (!tree.write (xml_path))
3701 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3703 if (g_remove (xml_path.c_str()) != 0) {
3704 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3705 xml_path, g_strerror (errno)) << endmsg;
3707 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3708 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3709 backup_path, g_strerror (errno)) << endmsg;
3719 Session::restore_history (string snapshot_name)
3723 if (snapshot_name.empty()) {
3724 snapshot_name = _current_snapshot_name;
3727 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3728 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3730 info << "Loading history from " << xml_path << endmsg;
3732 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3733 info << string_compose (_("%1: no history file \"%2\" for this session."),
3734 _name, xml_path) << endmsg;
3738 if (!tree.read (xml_path)) {
3739 error << string_compose (_("Could not understand session history file \"%1\""),
3740 xml_path) << endmsg;
3747 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); ++it) {
3750 UndoTransaction* ut = new UndoTransaction ();
3753 ut->set_name(t->property("name")->value());
3754 stringstream ss(t->property("tv-sec")->value());
3756 ss.str(t->property("tv-usec")->value());
3758 ut->set_timestamp(tv);
3760 for (XMLNodeConstIterator child_it = t->children().begin();
3761 child_it != t->children().end(); child_it++)
3763 XMLNode *n = *child_it;
3766 if (n->name() == "MementoCommand" ||
3767 n->name() == "MementoUndoCommand" ||
3768 n->name() == "MementoRedoCommand") {
3770 if ((c = memento_command_factory(n))) {
3774 } else if (n->name() == "NoteDiffCommand") {
3775 PBD::ID id (n->property("midi-source")->value());
3776 boost::shared_ptr<MidiSource> midi_source =
3777 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3779 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3781 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3784 } else if (n->name() == "SysExDiffCommand") {
3786 PBD::ID id (n->property("midi-source")->value());
3787 boost::shared_ptr<MidiSource> midi_source =
3788 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3790 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3792 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3795 } else if (n->name() == "PatchChangeDiffCommand") {
3797 PBD::ID id (n->property("midi-source")->value());
3798 boost::shared_ptr<MidiSource> midi_source =
3799 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3801 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3803 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3806 } else if (n->name() == "StatefulDiffCommand") {
3807 if ((c = stateful_diff_command_factory (n))) {
3808 ut->add_command (c);
3811 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3822 Session::config_changed (std::string p, bool ours)
3828 if (p == "seamless-loop") {
3830 } else if (p == "rf-speed") {
3832 } else if (p == "auto-loop") {
3834 } else if (p == "auto-input") {
3836 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3837 /* auto-input only makes a difference if we're rolling */
3838 set_track_monitor_input_status (!config.get_auto_input());
3841 } else if (p == "punch-in") {
3845 if ((location = _locations->auto_punch_location()) != 0) {
3847 if (config.get_punch_in ()) {
3848 replace_event (SessionEvent::PunchIn, location->start());
3850 remove_event (location->start(), SessionEvent::PunchIn);
3854 } else if (p == "punch-out") {
3858 if ((location = _locations->auto_punch_location()) != 0) {
3860 if (config.get_punch_out()) {
3861 replace_event (SessionEvent::PunchOut, location->end());
3863 clear_events (SessionEvent::PunchOut);
3867 } else if (p == "edit-mode") {
3869 Glib::Threads::Mutex::Lock lm (playlists->lock);
3871 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3872 (*i)->set_edit_mode (Config->get_edit_mode ());
3875 } else if (p == "use-video-sync") {
3877 waiting_for_sync_offset = config.get_use_video_sync();
3879 } else if (p == "mmc-control") {
3881 //poke_midi_thread ();
3883 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3885 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3887 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3889 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3891 } else if (p == "midi-control") {
3893 //poke_midi_thread ();
3895 } else if (p == "raid-path") {
3897 setup_raid_path (config.get_raid_path());
3899 } else if (p == "timecode-format") {
3903 } else if (p == "video-pullup") {
3907 } else if (p == "seamless-loop") {
3909 if (play_loop && transport_rolling()) {
3910 // to reset diskstreams etc
3911 request_play_loop (true);
3914 } else if (p == "rf-speed") {
3916 cumulative_rf_motion = 0;
3919 } else if (p == "click-sound") {
3921 setup_click_sounds (1);
3923 } else if (p == "click-emphasis-sound") {
3925 setup_click_sounds (-1);
3927 } else if (p == "clicking") {
3929 if (Config->get_clicking()) {
3930 if (_click_io && click_data) { // don't require emphasis data
3937 } else if (p == "click-gain") {
3940 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3943 } else if (p == "send-mtc") {
3945 if (Config->get_send_mtc ()) {
3946 /* mark us ready to send */
3947 next_quarter_frame_to_send = 0;
3950 } else if (p == "send-mmc") {
3952 _mmc->enable_send (Config->get_send_mmc ());
3954 } else if (p == "midi-feedback") {
3956 session_midi_feedback = Config->get_midi_feedback();
3958 } else if (p == "jack-time-master") {
3960 engine().reset_timebase ();
3962 } else if (p == "native-file-header-format") {
3964 if (!first_file_header_format_reset) {
3965 reset_native_file_format ();
3968 first_file_header_format_reset = false;
3970 } else if (p == "native-file-data-format") {
3972 if (!first_file_data_format_reset) {
3973 reset_native_file_format ();
3976 first_file_data_format_reset = false;
3978 } else if (p == "external-sync") {
3979 if (!config.get_external_sync()) {
3980 drop_sync_source ();
3982 switch_to_sync_source (Config->get_sync_source());
3984 } else if (p == "denormal-model") {
3986 } else if (p == "history-depth") {
3987 set_history_depth (Config->get_history_depth());
3988 } else if (p == "remote-model") {
3989 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3992 } else if (p == "initial-program-change") {
3994 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3997 buf[0] = MIDI::program; // channel zero by default
3998 buf[1] = (Config->get_initial_program_change() & 0x7f);
4000 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
4002 } else if (p == "solo-mute-override") {
4003 // catch_up_on_solo_mute_override ();
4004 } else if (p == "listen-position" || p == "pfl-position") {
4005 listen_position_changed ();
4006 } else if (p == "solo-control-is-listen-control") {
4007 solo_control_mode_changed ();
4008 } else if (p == "solo-mute-gain") {
4009 _solo_cut_control->Changed (true, Controllable::NoGroup);
4010 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
4011 last_timecode_valid = false;
4012 } else if (p == "playback-buffer-seconds") {
4013 AudioSource::allocate_working_buffers (frame_rate());
4014 } else if (p == "ltc-source-port") {
4015 reconnect_ltc_input ();
4016 } else if (p == "ltc-sink-port") {
4017 reconnect_ltc_output ();
4018 } else if (p == "timecode-generator-offset") {
4019 ltc_tx_parse_offset();
4020 } else if (p == "auto-return-target-list") {
4021 follow_playhead_priority ();
4028 Session::set_history_depth (uint32_t d)
4030 _history.set_depth (d);
4034 Session::load_diskstreams_2X (XMLNode const & node, int)
4037 XMLNodeConstIterator citer;
4039 clist = node.children();
4041 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4044 /* diskstreams added automatically by DiskstreamCreated handler */
4045 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4046 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4047 _diskstreams_2X.push_back (dsp);
4049 error << _("Session: unknown diskstream type in XML") << endmsg;
4053 catch (failed_constructor& err) {
4054 error << _("Session: could not load diskstream via XML state") << endmsg;
4062 /** Connect things to the MMC object */
4064 Session::setup_midi_machine_control ()
4066 _mmc = new MIDI::MachineControl;
4068 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4069 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4071 if (!async_out || !async_out) {
4075 /* XXXX argh, passing raw pointers back into libmidi++ */
4077 MIDI::Port* mmc_in = async_in.get();
4078 MIDI::Port* mmc_out = async_out.get();
4080 _mmc->set_ports (mmc_in, mmc_out);
4082 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4083 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4084 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4085 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4086 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4087 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4088 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4089 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4090 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4091 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4092 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4093 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4094 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4096 /* also handle MIDI SPP because its so common */
4098 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4099 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4100 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4103 boost::shared_ptr<Controllable>
4104 Session::solo_cut_control() const
4106 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4107 controls in Ardour that currently get presented to the user in the GUI that require
4108 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4110 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4111 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4115 return _solo_cut_control;
4119 Session::save_snapshot_name (const std::string & n)
4121 /* assure Stateful::_instant_xml is loaded
4122 * add_instant_xml() only adds to existing data and defaults
4123 * to use an empty Tree otherwise
4125 instant_xml ("LastUsedSnapshot");
4127 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4128 last_used_snapshot->add_property ("name", string(n));
4129 add_instant_xml (*last_used_snapshot, false);
4133 Session::set_snapshot_name (const std::string & n)
4135 _current_snapshot_name = n;
4136 save_snapshot_name (n);
4140 Session::rename (const std::string& new_name)
4142 string legal_name = legalize_for_path (new_name);
4148 string const old_sources_root = _session_dir->sources_root();
4150 if (!_writable || (_state_of_the_state & CannotSave)) {
4151 error << _("Cannot rename read-only session.") << endmsg;
4152 return 0; // don't show "messed up" warning
4154 if (record_status() == Recording) {
4155 error << _("Cannot rename session while recording") << endmsg;
4156 return 0; // don't show "messed up" warning
4159 StateProtector stp (this);
4164 * interchange subdirectory
4168 * Backup files are left unchanged and not renamed.
4171 /* Windows requires that we close all files before attempting the
4172 * rename. This works on other platforms, but isn't necessary there.
4173 * Leave it in place for all platforms though, since it may help
4174 * catch issues that could arise if the way Source files work ever
4175 * change (since most developers are not using Windows).
4178 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4179 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4185 /* pass one: not 100% safe check that the new directory names don't
4189 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4193 /* this is a stupid hack because Glib::path_get_dirname() is
4194 * lexical-only, and so passing it /a/b/c/ gives a different
4195 * result than passing it /a/b/c ...
4198 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4199 oldstr = oldstr.substr (0, oldstr.length() - 1);
4202 string base = Glib::path_get_dirname (oldstr);
4204 newstr = Glib::build_filename (base, legal_name);
4206 cerr << "Looking for " << newstr << endl;
4208 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4209 cerr << " exists\n";
4218 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4224 /* this is a stupid hack because Glib::path_get_dirname() is
4225 * lexical-only, and so passing it /a/b/c/ gives a different
4226 * result than passing it /a/b/c ...
4229 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4230 oldstr = oldstr.substr (0, oldstr.length() - 1);
4233 string base = Glib::path_get_dirname (oldstr);
4234 newstr = Glib::build_filename (base, legal_name);
4236 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4238 cerr << "Rename " << oldstr << " => " << newstr << endl;
4239 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4240 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4241 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4245 /* Reset path in "session dirs" */
4250 /* reset primary SessionDirectory object */
4253 (*_session_dir) = newstr;
4258 /* now rename directory below session_dir/interchange */
4260 string old_interchange_dir;
4261 string new_interchange_dir;
4263 /* use newstr here because we renamed the path
4264 * (folder/directory) that used to be oldstr to newstr above
4267 v.push_back (newstr);
4268 v.push_back (interchange_dir_name);
4269 v.push_back (Glib::path_get_basename (oldstr));
4271 old_interchange_dir = Glib::build_filename (v);
4274 v.push_back (newstr);
4275 v.push_back (interchange_dir_name);
4276 v.push_back (legal_name);
4278 new_interchange_dir = Glib::build_filename (v);
4280 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4282 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4283 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4284 old_interchange_dir, new_interchange_dir,
4287 error << string_compose (_("renaming %s as %2 failed (%3)"),
4288 old_interchange_dir, new_interchange_dir,
4297 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4298 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4300 cerr << "Rename " << oldstr << " => " << newstr << endl;
4302 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4303 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4304 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4310 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4312 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4313 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4315 cerr << "Rename " << oldstr << " => " << newstr << endl;
4317 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4318 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4319 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4324 /* remove old name from recent sessions */
4325 remove_recent_sessions (_path);
4328 /* update file source paths */
4330 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4331 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4333 string p = fs->path ();
4334 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4336 SourceFactory::setup_peakfile(i->second, true);
4340 set_snapshot_name (new_name);
4345 /* save state again to get everything just right */
4347 save_state (_current_snapshot_name);
4349 /* add to recent sessions */
4351 store_recent_sessions (new_name, _path);
4357 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4359 bool found_sr = false;
4360 bool found_data_format = false;
4362 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4366 xmlParserCtxtPtr ctxt = xmlNewParserCtxt();
4370 xmlDocPtr doc = xmlCtxtReadFile (ctxt, xmlpath.c_str(), NULL, XML_PARSE_HUGE);
4373 xmlFreeParserCtxt(ctxt);
4377 xmlNodePtr node = xmlDocGetRootElement(doc);
4380 xmlFreeParserCtxt(ctxt);
4387 for (attr = node->properties; attr; attr = attr->next) {
4388 if (!strcmp ((const char*)attr->name, "sample-rate") && attr->children) {
4389 sample_rate = atoi ((char*)attr->children->content);
4394 node = node->children;
4395 while (node != NULL) {
4396 if (strcmp((const char*) node->name, "Config")) {
4400 for (node = node->children; node; node = node->next) {
4401 xmlChar* pv = xmlGetProp (node, (const xmlChar*)"name");
4402 if (pv && !strcmp ((const char*)pv, "native-file-data-format")) {
4404 xmlChar* val = xmlGetProp (node, (const xmlChar*)"value");
4406 SampleFormat fmt = (SampleFormat) string_2_enum (string ((const char*)val), fmt);
4408 found_data_format = true;
4418 xmlFreeParserCtxt(ctxt);
4420 return !(found_sr && found_data_format); // zero if they are both found
4424 Session::get_snapshot_from_instant (const std::string& session_dir)
4426 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4428 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4433 if (!tree.read (instant_xml_path)) {
4437 XMLProperty const * prop;
4438 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4439 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4440 return prop->value();
4446 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4447 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4450 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4454 SourcePathMap source_path_map;
4456 boost::shared_ptr<AudioFileSource> afs;
4461 Glib::Threads::Mutex::Lock lm (source_lock);
4463 cerr << " total sources = " << sources.size();
4465 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4466 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4472 if (fs->within_session()) {
4476 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4477 source_path_map[fs->path()].push_back (fs);
4479 SeveralFileSources v;
4481 source_path_map.insert (make_pair (fs->path(), v));
4487 cerr << " fsources = " << total << endl;
4489 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4491 /* tell caller where we are */
4493 string old_path = i->first;
4495 callback (n, total, old_path);
4497 cerr << old_path << endl;
4501 switch (i->second.front()->type()) {
4502 case DataType::AUDIO:
4503 new_path = new_audio_source_path_for_embedded (old_path);
4506 case DataType::MIDI:
4507 /* XXX not implemented yet */
4511 if (new_path.empty()) {
4515 cerr << "Move " << old_path << " => " << new_path << endl;
4517 if (!copy_file (old_path, new_path)) {
4518 cerr << "failed !\n";
4522 /* make sure we stop looking in the external
4523 dir/folder. Remember, this is an all-or-nothing
4524 operations, it doesn't merge just some files.
4526 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4528 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4529 (*f)->set_path (new_path);
4534 save_state ("", false, false);
4540 bool accept_all_files (string const &, void *)
4546 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4548 /* 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.
4553 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4555 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4557 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4559 v.push_back (new_session_folder); /* full path */
4560 v.push_back (interchange_dir_name);
4561 v.push_back (new_session_path); /* just one directory/folder */
4562 v.push_back (typedir);
4563 v.push_back (Glib::path_get_basename (old_path));
4565 return Glib::build_filename (v);
4569 Session::save_as (SaveAs& saveas)
4571 vector<string> files;
4572 string current_folder = Glib::path_get_dirname (_path);
4573 string new_folder = legalize_for_path (saveas.new_name);
4574 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4575 int64_t total_bytes = 0;
4579 int32_t internal_file_cnt = 0;
4581 vector<string> do_not_copy_extensions;
4582 do_not_copy_extensions.push_back (statefile_suffix);
4583 do_not_copy_extensions.push_back (pending_suffix);
4584 do_not_copy_extensions.push_back (backup_suffix);
4585 do_not_copy_extensions.push_back (temp_suffix);
4586 do_not_copy_extensions.push_back (history_suffix);
4588 /* get total size */
4590 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4592 /* need to clear this because
4593 * find_files_matching_filter() is cumulative
4598 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4600 all += files.size();
4602 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4604 g_stat ((*i).c_str(), &gsb);
4605 total_bytes += gsb.st_size;
4609 /* save old values so we can switch back if we are not switching to the new session */
4611 string old_path = _path;
4612 string old_name = _name;
4613 string old_snapshot = _current_snapshot_name;
4614 string old_sd = _session_dir->root_path();
4615 vector<string> old_search_path[DataType::num_types];
4616 string old_config_search_path[DataType::num_types];
4618 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4619 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4620 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4621 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4623 /* switch session directory */
4625 (*_session_dir) = to_dir;
4627 /* create new tree */
4629 if (!_session_dir->create()) {
4630 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4635 /* copy all relevant files. Find each location in session_dirs,
4636 * and copy files from there to target.
4639 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4641 /* need to clear this because
4642 * find_files_matching_filter() is cumulative
4647 const size_t prefix_len = (*sd).path.size();
4649 /* Work just on the files within this session dir */
4651 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4653 /* add dir separator to protect against collisions with
4654 * track names (e.g. track named "audiofiles" or
4658 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4659 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4660 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4662 /* copy all the files. Handling is different for media files
4663 than others because of the *silly* subtree we have below the interchange
4664 folder. That really was a bad idea, but I'm not fixing it as part of
4665 implementing ::save_as().
4668 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4670 std::string from = *i;
4673 string filename = Glib::path_get_basename (from);
4674 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4675 if (filename == ".DS_STORE") {
4680 if (from.find (audiofile_dir_string) != string::npos) {
4682 /* audio file: only copy if asked */
4684 if (saveas.include_media && saveas.copy_media) {
4686 string to = make_new_media_path (*i, to_dir, new_folder);
4688 info << "media file copying from " << from << " to " << to << endmsg;
4690 if (!copy_file (from, to)) {
4691 throw Glib::FileError (Glib::FileError::IO_ERROR,
4692 string_compose(_("\ncopying \"%1\" failed !"), from));
4696 /* we found media files inside the session folder */
4698 internal_file_cnt++;
4700 } else if (from.find (midifile_dir_string) != string::npos) {
4702 /* midi file: always copy unless
4703 * creating an empty new session
4706 if (saveas.include_media) {
4708 string to = make_new_media_path (*i, to_dir, new_folder);
4710 info << "media file copying from " << from << " to " << to << endmsg;
4712 if (!copy_file (from, to)) {
4713 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4717 /* we found media files inside the session folder */
4719 internal_file_cnt++;
4721 } else if (from.find (analysis_dir_string) != string::npos) {
4723 /* make sure analysis dir exists in
4724 * new session folder, but we're not
4725 * copying analysis files here, see
4729 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4734 /* normal non-media file. Don't copy state, history, etc.
4737 bool do_copy = true;
4739 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4740 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4741 /* end of filename matches extension, do not copy file */
4747 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4748 /* don't copy peakfiles if
4749 * we're not copying media
4755 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4757 info << "attempting to make directory/folder " << to << endmsg;
4759 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4760 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4763 info << "attempting to copy " << from << " to " << to << endmsg;
4765 if (!copy_file (from, to)) {
4766 throw Glib::FileError (Glib::FileError::IO_ERROR,
4767 string_compose(_("\ncopying \"%1\" failed !"), from));
4772 /* measure file size even if we're not going to copy so that our Progress
4773 signals are correct, since we included these do-not-copy files
4774 in the computation of the total size and file count.
4778 g_stat (from.c_str(), &gsb);
4779 copied += gsb.st_size;
4782 double fraction = (double) copied / total_bytes;
4784 bool keep_going = true;
4786 if (saveas.copy_media) {
4788 /* no need or expectation of this if
4789 * media is not being copied, because
4790 * it will be fast(ish).
4793 /* tell someone "X percent, file M of N"; M is one-based */
4795 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4803 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4809 /* copy optional folders, if any */
4811 string old = plugins_dir ();
4812 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4813 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4814 copy_files (old, newdir);
4817 old = externals_dir ();
4818 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4819 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4820 copy_files (old, newdir);
4823 old = automation_dir ();
4824 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4825 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4826 copy_files (old, newdir);
4829 if (saveas.include_media) {
4831 if (saveas.copy_media) {
4832 #ifndef PLATFORM_WINDOWS
4833 /* There are problems with analysis files on
4834 * Windows, because they used a colon in their
4835 * names as late as 4.0. Colons are not legal
4836 * under Windows even if NTFS allows them.
4838 * This is a tricky problem to solve so for
4839 * just don't copy these files. They will be
4840 * regenerated as-needed anyway, subject to the
4841 * existing issue that the filenames will be
4842 * rejected by Windows, which is a separate
4843 * problem (though related).
4846 /* only needed if we are copying media, since the
4847 * analysis data refers to media data
4850 old = analysis_dir ();
4851 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4852 string newdir = Glib::build_filename (to_dir, "analysis");
4853 copy_files (old, newdir);
4855 #endif /* PLATFORM_WINDOWS */
4861 set_snapshot_name (saveas.new_name);
4862 _name = saveas.new_name;
4864 if (saveas.include_media && !saveas.copy_media) {
4866 /* reset search paths of the new session (which we're pretending to be right now) to
4867 include the original session search path, so we can still find all audio.
4870 if (internal_file_cnt) {
4871 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4872 ensure_search_path_includes (*s, DataType::AUDIO);
4873 cerr << "be sure to include " << *s << " for audio" << endl;
4876 /* we do not do this for MIDI because we copy
4877 all MIDI files if saveas.include_media is
4883 bool was_dirty = dirty ();
4885 save_state ("", false, false, !saveas.include_media);
4886 save_default_options ();
4888 if (saveas.copy_media && saveas.copy_external) {
4889 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4890 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4894 saveas.final_session_folder_name = _path;
4896 store_recent_sessions (_name, _path);
4898 if (!saveas.switch_to) {
4900 /* switch back to the way things were */
4904 set_snapshot_name (old_snapshot);
4906 (*_session_dir) = old_sd;
4912 if (internal_file_cnt) {
4913 /* reset these to their original values */
4914 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4915 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4920 /* prune session dirs, and update disk space statistics
4925 session_dirs.clear ();
4926 session_dirs.push_back (sp);
4927 refresh_disk_space ();
4929 /* ensure that all existing tracks reset their current capture source paths
4931 reset_write_sources (true, true);
4933 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4934 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4937 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4938 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4944 if (fs->within_session()) {
4945 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4946 fs->set_path (newpath);
4951 } catch (Glib::FileError& e) {
4953 saveas.failure_message = e.what();
4955 /* recursively remove all the directories */
4957 remove_directory (to_dir);
4965 saveas.failure_message = _("unknown reason");
4967 /* recursively remove all the directories */
4969 remove_directory (to_dir);
4979 static void set_progress (Progress* p, size_t n, size_t t)
4981 p->set_progress (float (n) / float(t));
4985 Session::archive_session (const std::string& dest,
4986 const std::string& name,
4987 ArchiveEncode compress_audio,
4988 bool only_used_sources,
4991 if (dest.empty () || name.empty ()) {
4995 /* save current values */
4996 bool was_dirty = dirty ();
4997 string old_path = _path;
4998 string old_name = _name;
4999 string old_snapshot = _current_snapshot_name;
5000 string old_sd = _session_dir->root_path();
5001 string old_config_search_path[DataType::num_types];
5002 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
5003 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
5005 /* ensure that session-path is included in search-path */
5007 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5008 if ((*sd).path == old_path) {
5016 /* create temporary dir to save session to */
5017 #ifdef PLATFORM_WINDOWS
5018 char tmp[256] = "C:\\TEMP\\";
5019 GetTempPath (sizeof (tmp), tmp);
5021 char const* tmp = getenv("TMPDIR");
5026 if ((strlen (tmp) + 21) > 1024) {
5031 strcpy (tmptpl, tmp);
5032 strcat (tmptpl, "ardourarchive-XXXXXX");
5033 char* tmpdir = g_mkdtemp (tmptpl);
5039 std::string to_dir = std::string (tmpdir);
5041 /* switch session directory temporarily */
5042 (*_session_dir) = to_dir;
5044 if (!_session_dir->create()) {
5045 (*_session_dir) = old_sd;
5046 remove_directory (to_dir);
5050 /* prepare archive */
5051 string archive = Glib::build_filename (dest, name + ".tar.xz");
5053 PBD::ScopedConnectionList progress_connection;
5054 PBD::FileArchive ar (archive);
5056 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5059 /* collect files to archive */
5060 std::map<string,string> filemap;
5062 vector<string> do_not_copy_extensions;
5063 do_not_copy_extensions.push_back (statefile_suffix);
5064 do_not_copy_extensions.push_back (pending_suffix);
5065 do_not_copy_extensions.push_back (backup_suffix);
5066 do_not_copy_extensions.push_back (temp_suffix);
5067 do_not_copy_extensions.push_back (history_suffix);
5069 vector<string> blacklist_dirs;
5070 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5071 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5072 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5073 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5074 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5075 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5077 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5078 std::map<boost::shared_ptr<AudioFileSource>, float> orig_gain;
5080 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5081 if (only_used_sources) {
5082 playlists->sync_all_regions_with_regions ();
5083 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5086 // collect audio sources for this session, calc total size for encoding
5087 // add option to only include *used* sources (see Session::cleanup_sources)
5088 size_t total_size = 0;
5090 Glib::Threads::Mutex::Lock lm (source_lock);
5091 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5092 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5093 if (!afs || afs->readable_length () == 0) {
5097 if (only_used_sources) {
5101 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5106 std::string from = afs->path();
5108 if (compress_audio != NO_ENCODE) {
5109 total_size += afs->readable_length ();
5111 if (afs->within_session()) {
5112 filemap[from] = make_new_media_path (from, name, name);
5114 filemap[from] = make_new_media_path (from, name, name);
5115 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5122 if (compress_audio != NO_ENCODE) {
5124 progress->set_progress (2); // set to "encoding"
5125 progress->set_progress (0);
5128 Glib::Threads::Mutex::Lock lm (source_lock);
5129 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5130 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5131 if (!afs || afs->readable_length () == 0) {
5135 if (only_used_sources) {
5139 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5144 orig_sources[afs] = afs->path();
5145 orig_gain[afs] = afs->gain();
5147 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5148 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5149 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5152 progress->descend ((float)afs->readable_length () / total_size);
5156 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5157 afs->replace_file (new_path);
5158 afs->set_gain (ns->gain(), true);
5161 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5165 progress->ascend ();
5171 progress->set_progress (-1); // set to "archiving"
5172 progress->set_progress (0);
5175 /* index files relevant for this session */
5176 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5177 vector<string> files;
5179 size_t prefix_len = (*sd).path.size();
5180 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5184 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5186 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5187 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5188 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5190 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5191 std::string from = *i;
5194 string filename = Glib::path_get_basename (from);
5195 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5196 if (filename == ".DS_STORE") {
5201 if (from.find (audiofile_dir_string) != string::npos) {
5203 } else if (from.find (midifile_dir_string) != string::npos) {
5204 filemap[from] = make_new_media_path (from, name, name);
5205 } else if (from.find (videofile_dir_string) != string::npos) {
5206 filemap[from] = make_new_media_path (from, name, name);
5208 bool do_copy = true;
5209 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5210 if (from.find (*v) != string::npos) {
5215 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5216 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5223 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5229 /* write session file */
5231 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5233 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5235 save_default_options ();
5237 size_t prefix_len = _path.size();
5238 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5242 /* collect session-state files */
5243 vector<string> files;
5244 do_not_copy_extensions.clear ();
5245 do_not_copy_extensions.push_back (history_suffix);
5247 blacklist_dirs.clear ();
5248 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5250 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5251 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5252 std::string from = *i;
5253 bool do_copy = true;
5254 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5255 if (from.find (*v) != string::npos) {
5260 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5261 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5267 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5271 /* restore original values */
5274 set_snapshot_name (old_snapshot);
5275 (*_session_dir) = old_sd;
5279 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5280 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5282 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5283 i->first->replace_file (i->second);
5285 for (std::map<boost::shared_ptr<AudioFileSource>, float>::iterator i = orig_gain.begin (); i != orig_gain.end (); ++i) {
5286 i->first->set_gain (i->second, true);
5289 int rv = ar.create (filemap);
5290 remove_directory (to_dir);
5296 Session::undo (uint32_t n)
5298 if (actively_recording()) {
5306 Session::redo (uint32_t n)
5308 if (actively_recording()) {