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);
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);
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::add_route_group (RouteGroup* g)
2624 _route_groups.push_back (g);
2625 route_group_added (g); /* EMIT SIGNAL */
2627 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2628 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2629 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2635 Session::remove_route_group (RouteGroup& rg)
2637 list<RouteGroup*>::iterator i;
2639 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2640 _route_groups.erase (i);
2643 route_group_removed (); /* EMIT SIGNAL */
2647 /** Set a new order for our route groups, without adding or removing any.
2648 * @param groups Route group list in the new order.
2651 Session::reorder_route_groups (list<RouteGroup*> groups)
2653 _route_groups = groups;
2655 route_groups_reordered (); /* EMIT SIGNAL */
2661 Session::route_group_by_name (string name)
2663 list<RouteGroup *>::iterator i;
2665 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2666 if ((*i)->name() == name) {
2674 Session::all_route_group() const
2676 return *_all_route_group;
2680 Session::add_commands (vector<Command*> const & cmds)
2682 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2688 Session::add_command (Command* const cmd)
2690 assert (_current_trans);
2691 DEBUG_UNDO_HISTORY (
2692 string_compose ("Current Undo Transaction %1, adding command: %2",
2693 _current_trans->name (),
2695 _current_trans->add_command (cmd);
2698 PBD::StatefulDiffCommand*
2699 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2701 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2707 Session::begin_reversible_command (const string& name)
2709 begin_reversible_command (g_quark_from_string (name.c_str ()));
2712 /** Begin a reversible command using a GQuark to identify it.
2713 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2714 * but there must be as many begin...()s as there are commit...()s.
2717 Session::begin_reversible_command (GQuark q)
2719 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2720 to hold all the commands that are committed. This keeps the order of
2721 commands correct in the history.
2724 if (_current_trans == 0) {
2725 DEBUG_UNDO_HISTORY (string_compose (
2726 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2728 /* start a new transaction */
2729 assert (_current_trans_quarks.empty ());
2730 _current_trans = new UndoTransaction();
2731 _current_trans->set_name (g_quark_to_string (q));
2733 DEBUG_UNDO_HISTORY (
2734 string_compose ("Begin Reversible Command, current transaction: %1",
2735 _current_trans->name ()));
2738 _current_trans_quarks.push_front (q);
2742 Session::abort_reversible_command ()
2744 if (_current_trans != 0) {
2745 DEBUG_UNDO_HISTORY (
2746 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2747 _current_trans->clear();
2748 delete _current_trans;
2750 _current_trans_quarks.clear();
2755 Session::commit_reversible_command (Command *cmd)
2757 assert (_current_trans);
2758 assert (!_current_trans_quarks.empty ());
2763 DEBUG_UNDO_HISTORY (
2764 string_compose ("Current Undo Transaction %1, adding command: %2",
2765 _current_trans->name (),
2767 _current_trans->add_command (cmd);
2770 DEBUG_UNDO_HISTORY (
2771 string_compose ("Commit Reversible Command, current transaction: %1",
2772 _current_trans->name ()));
2774 _current_trans_quarks.pop_front ();
2776 if (!_current_trans_quarks.empty ()) {
2777 DEBUG_UNDO_HISTORY (
2778 string_compose ("Commit Reversible Command, transaction is not "
2779 "top-level, current transaction: %1",
2780 _current_trans->name ()));
2781 /* the transaction we're committing is not the top-level one */
2785 if (_current_trans->empty()) {
2786 /* no commands were added to the transaction, so just get rid of it */
2787 DEBUG_UNDO_HISTORY (
2788 string_compose ("Commit Reversible Command, No commands were "
2789 "added to current transaction: %1",
2790 _current_trans->name ()));
2791 delete _current_trans;
2796 gettimeofday (&now, 0);
2797 _current_trans->set_timestamp (now);
2799 _history.add (_current_trans);
2804 accept_all_audio_files (const string& path, void* /*arg*/)
2806 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2810 if (!AudioFileSource::safe_audio_file_extension (path)) {
2818 accept_all_midi_files (const string& path, void* /*arg*/)
2820 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2824 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2825 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2826 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2830 accept_all_state_files (const string& path, void* /*arg*/)
2832 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2836 std::string const statefile_ext (statefile_suffix);
2837 if (path.length() >= statefile_ext.length()) {
2838 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2845 Session::find_all_sources (string path, set<string>& result)
2850 if (!tree.read (path)) {
2854 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2859 XMLNodeConstIterator niter;
2861 nlist = node->children();
2865 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2867 XMLProperty const * prop;
2869 if ((prop = (*niter)->property (X_("type"))) == 0) {
2873 DataType type (prop->value());
2875 if ((prop = (*niter)->property (X_("name"))) == 0) {
2879 if (Glib::path_is_absolute (prop->value())) {
2880 /* external file, ignore */
2888 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2889 result.insert (found_path);
2897 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2899 vector<string> state_files;
2901 string this_snapshot_path;
2907 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2908 ripped = ripped.substr (0, ripped.length() - 1);
2911 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2913 if (state_files.empty()) {
2918 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2919 this_snapshot_path += statefile_suffix;
2921 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2923 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2925 if (exclude_this_snapshot && *i == this_snapshot_path) {
2926 cerr << "\texcluded\n";
2931 if (find_all_sources (*i, result) < 0) {
2939 struct RegionCounter {
2940 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2941 AudioSourceList::iterator iter;
2942 boost::shared_ptr<Region> region;
2945 RegionCounter() : count (0) {}
2949 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2951 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2952 return r.get_value_or (1);
2956 Session::cleanup_regions ()
2958 bool removed = false;
2959 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2961 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2963 uint32_t used = playlists->region_use_count (i->second);
2965 if (used == 0 && !i->second->automatic ()) {
2966 boost::weak_ptr<Region> w = i->second;
2969 RegionFactory::map_remove (w);
2976 // re-check to remove parent references of compound regions
2977 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2978 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2982 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2983 if (0 == playlists->region_use_count (i->second)) {
2984 boost::weak_ptr<Region> w = i->second;
2986 RegionFactory::map_remove (w);
2993 /* dump the history list */
3000 Session::can_cleanup_peakfiles () const
3002 if (deletion_in_progress()) {
3005 if (!_writable || (_state_of_the_state & CannotSave)) {
3006 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
3009 if (record_status() == Recording) {
3010 error << _("Cannot cleanup peak-files while recording") << endmsg;
3017 Session::cleanup_peakfiles ()
3019 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
3024 assert (can_cleanup_peakfiles ());
3025 assert (!peaks_cleanup_in_progres());
3027 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3029 int timeout = 5000; // 5 seconds
3030 while (!SourceFactory::files_with_peaks.empty()) {
3031 Glib::usleep (1000);
3032 if (--timeout < 0) {
3033 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3034 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3039 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3040 boost::shared_ptr<AudioSource> as;
3041 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3042 as->close_peakfile();
3046 PBD::clear_directory (session_directory().peak_path());
3048 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3050 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3051 boost::shared_ptr<AudioSource> as;
3052 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3053 SourceFactory::setup_peakfile(as, true);
3060 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3062 pl->deep_sources (*all_sources);
3066 Session::cleanup_sources (CleanupReport& rep)
3068 // FIXME: needs adaptation to midi
3070 vector<boost::shared_ptr<Source> > dead_sources;
3073 vector<string> candidates;
3074 vector<string> unused;
3075 set<string> sources_used_by_all_snapshots;
3082 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3084 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3086 /* this is mostly for windows which doesn't allow file
3087 * renaming if the file is in use. But we don't special
3088 * case it because we need to know if this causes
3089 * problems, and the easiest way to notice that is to
3090 * keep it in place for all platforms.
3093 request_stop (false);
3095 _butler->wait_until_finished ();
3097 /* consider deleting all unused playlists */
3099 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3104 /* sync the "all regions" property of each playlist with its current state
3107 playlists->sync_all_regions_with_regions ();
3109 /* find all un-used sources */
3114 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3116 SourceMap::iterator tmp;
3121 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3125 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3126 dead_sources.push_back (i->second);
3127 i->second->drop_references ();
3133 /* build a list of all the possible audio directories for the session */
3135 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3136 SessionDirectory sdir ((*i).path);
3137 asp += sdir.sound_path();
3139 audio_path += asp.to_string();
3142 /* build a list of all the possible midi directories for the session */
3144 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3145 SessionDirectory sdir ((*i).path);
3146 msp += sdir.midi_path();
3148 midi_path += msp.to_string();
3150 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3151 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3153 /* add sources from all other snapshots as "used", but don't use this
3154 snapshot because the state file on disk still references sources we
3155 may have already dropped.
3158 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3160 /* Although the region factory has a list of all regions ever created
3161 * for this session, we're only interested in regions actually in
3162 * playlists right now. So merge all playlist regions lists together.
3164 * This will include the playlists used within compound regions.
3167 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3169 /* add our current source list
3172 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3173 boost::shared_ptr<FileSource> fs;
3174 SourceMap::iterator tmp = i;
3177 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3183 /* this is mostly for windows which doesn't allow file
3184 * renaming if the file is in use. But we do not special
3185 * case it because we need to know if this causes
3186 * problems, and the easiest way to notice that is to
3187 * keep it in place for all platforms.
3192 if (!fs->is_stub()) {
3194 /* Note that we're checking a list of all
3195 * sources across all snapshots with the list
3196 * of sources used by this snapshot.
3199 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3200 /* this source is in use by this snapshot */
3201 sources_used_by_all_snapshots.insert (fs->path());
3202 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3204 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3205 /* this source is NOT in use by this snapshot
3208 /* remove all related regions from RegionFactory master list
3211 RegionFactory::remove_regions_using_source (i->second);
3213 /* remove from our current source list
3214 * also. We may not remove it from
3215 * disk, because it may be used by
3216 * other snapshots, but it isn't used inside this
3217 * snapshot anymore, so we don't need a
3228 /* now check each candidate source to see if it exists in the list of
3229 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3232 cerr << "Candidates: " << candidates.size() << endl;
3233 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3235 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3240 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3242 tmppath1 = canonical_path (spath);
3243 tmppath2 = canonical_path ((*i));
3245 cerr << "\t => " << tmppath2 << endl;
3247 if (tmppath1 == tmppath2) {
3254 unused.push_back (spath);
3258 cerr << "Actually unused: " << unused.size() << endl;
3260 if (unused.empty()) {
3266 /* now try to move all unused files into the "dead" directory(ies) */
3268 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3273 /* don't move the file across filesystems, just
3274 stick it in the `dead_dir_name' directory
3275 on whichever filesystem it was already on.
3278 if ((*x).find ("/sounds/") != string::npos) {
3280 /* old school, go up 1 level */
3282 newpath = Glib::path_get_dirname (*x); // "sounds"
3283 newpath = Glib::path_get_dirname (newpath); // "session-name"
3287 /* new school, go up 4 levels */
3289 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3290 newpath = Glib::path_get_dirname (newpath); // "session-name"
3291 newpath = Glib::path_get_dirname (newpath); // "interchange"
3292 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3295 newpath = Glib::build_filename (newpath, dead_dir_name);
3297 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3298 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3302 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3304 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3306 /* the new path already exists, try versioning */
3308 char buf[PATH_MAX+1];
3312 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3315 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3316 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3320 if (version == 999) {
3321 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3325 newpath = newpath_v;
3330 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3331 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3332 newpath, g_strerror (errno)) << endmsg;
3336 /* see if there an easy to find peakfile for this file, and remove it.
3339 string base = Glib::path_get_basename (*x);
3340 base += "%A"; /* this is what we add for the channel suffix of all native files,
3341 or for the first channel of embedded files. it will miss
3342 some peakfiles for other channels
3344 string peakpath = construct_peak_filepath (base);
3346 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3347 if (::g_unlink (peakpath.c_str ()) != 0) {
3348 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3349 g_strerror (errno)) << endmsg;
3350 /* try to back out */
3351 ::g_rename (newpath.c_str (), _path.c_str ());
3356 rep.paths.push_back (*x);
3357 rep.space += statbuf.st_size;
3360 /* dump the history list */
3364 /* save state so we don't end up a session file
3365 referring to non-existent sources.
3372 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3378 Session::cleanup_trash_sources (CleanupReport& rep)
3380 // FIXME: needs adaptation for MIDI
3382 vector<space_and_path>::iterator i;
3388 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3390 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3392 clear_directory (dead_dir, &rep.space, &rep.paths);
3399 Session::set_dirty ()
3401 /* never mark session dirty during loading */
3403 if (_state_of_the_state & Loading) {
3407 bool was_dirty = dirty();
3409 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3413 DirtyChanged(); /* EMIT SIGNAL */
3419 Session::set_clean ()
3421 bool was_dirty = dirty();
3423 _state_of_the_state = Clean;
3427 DirtyChanged(); /* EMIT SIGNAL */
3432 Session::set_deletion_in_progress ()
3434 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3438 Session::clear_deletion_in_progress ()
3440 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3444 Session::add_controllable (boost::shared_ptr<Controllable> c)
3446 /* this adds a controllable to the list managed by the Session.
3447 this is a subset of those managed by the Controllable class
3448 itself, and represents the only ones whose state will be saved
3449 as part of the session.
3452 Glib::Threads::Mutex::Lock lm (controllables_lock);
3453 controllables.insert (c);
3456 struct null_deleter { void operator()(void const *) const {} };
3459 Session::remove_controllable (Controllable* c)
3461 if (_state_of_the_state & Deletion) {
3465 Glib::Threads::Mutex::Lock lm (controllables_lock);
3467 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3469 if (x != controllables.end()) {
3470 controllables.erase (x);
3474 boost::shared_ptr<Controllable>
3475 Session::controllable_by_id (const PBD::ID& id)
3477 Glib::Threads::Mutex::Lock lm (controllables_lock);
3479 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3480 if ((*i)->id() == id) {
3485 return boost::shared_ptr<Controllable>();
3488 boost::shared_ptr<Controllable>
3489 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3491 boost::shared_ptr<Controllable> c;
3492 boost::shared_ptr<Stripable> s;
3493 boost::shared_ptr<Route> r;
3495 switch (desc.top_level_type()) {
3496 case ControllableDescriptor::NamedRoute:
3498 std::string str = desc.top_level_name();
3500 if (str == "Master" || str == "master") {
3502 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3504 } else if (str == "auditioner") {
3507 s = route_by_name (desc.top_level_name());
3513 case ControllableDescriptor::PresentationOrderRoute:
3514 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3517 case ControllableDescriptor::PresentationOrderTrack:
3518 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3521 case ControllableDescriptor::PresentationOrderBus:
3522 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3525 case ControllableDescriptor::PresentationOrderVCA:
3526 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3529 case ControllableDescriptor::SelectionCount:
3530 s = route_by_selected_count (desc.selection_id());
3538 r = boost::dynamic_pointer_cast<Route> (s);
3540 switch (desc.subtype()) {
3541 case ControllableDescriptor::Gain:
3542 c = s->gain_control ();
3545 case ControllableDescriptor::Trim:
3546 c = s->trim_control ();
3549 case ControllableDescriptor::Solo:
3550 c = s->solo_control();
3553 case ControllableDescriptor::Mute:
3554 c = s->mute_control();
3557 case ControllableDescriptor::Recenable:
3558 c = s->rec_enable_control ();
3561 case ControllableDescriptor::PanDirection:
3562 c = s->pan_azimuth_control();
3565 case ControllableDescriptor::PanWidth:
3566 c = s->pan_width_control();
3569 case ControllableDescriptor::PanElevation:
3570 c = s->pan_elevation_control();
3573 case ControllableDescriptor::Balance:
3574 /* XXX simple pan control */
3577 case ControllableDescriptor::PluginParameter:
3579 uint32_t plugin = desc.target (0);
3580 uint32_t parameter_index = desc.target (1);
3582 /* revert to zero based counting */
3588 if (parameter_index > 0) {
3596 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3599 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3600 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3605 case ControllableDescriptor::SendGain: {
3606 uint32_t send = desc.target (0);
3613 c = r->send_level_controllable (send);
3618 /* relax and return a null pointer */
3626 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3629 Stateful::add_instant_xml (node, _path);
3632 if (write_to_config) {
3633 Config->add_instant_xml (node);
3638 Session::instant_xml (const string& node_name)
3640 return Stateful::instant_xml (node_name, _path);
3644 Session::save_history (string snapshot_name)
3652 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3653 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3657 if (snapshot_name.empty()) {
3658 snapshot_name = _current_snapshot_name;
3661 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3662 const string backup_filename = history_filename + backup_suffix;
3663 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3664 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3666 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3667 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3668 error << _("could not backup old history file, current history not saved") << endmsg;
3673 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3675 if (!tree.write (xml_path))
3677 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3679 if (g_remove (xml_path.c_str()) != 0) {
3680 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3681 xml_path, g_strerror (errno)) << endmsg;
3683 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3684 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3685 backup_path, g_strerror (errno)) << endmsg;
3695 Session::restore_history (string snapshot_name)
3699 if (snapshot_name.empty()) {
3700 snapshot_name = _current_snapshot_name;
3703 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3704 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3706 info << "Loading history from " << xml_path << endmsg;
3708 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3709 info << string_compose (_("%1: no history file \"%2\" for this session."),
3710 _name, xml_path) << endmsg;
3714 if (!tree.read (xml_path)) {
3715 error << string_compose (_("Could not understand session history file \"%1\""),
3716 xml_path) << endmsg;
3723 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3726 UndoTransaction* ut = new UndoTransaction ();
3729 ut->set_name(t->property("name")->value());
3730 stringstream ss(t->property("tv-sec")->value());
3732 ss.str(t->property("tv-usec")->value());
3734 ut->set_timestamp(tv);
3736 for (XMLNodeConstIterator child_it = t->children().begin();
3737 child_it != t->children().end(); child_it++)
3739 XMLNode *n = *child_it;
3742 if (n->name() == "MementoCommand" ||
3743 n->name() == "MementoUndoCommand" ||
3744 n->name() == "MementoRedoCommand") {
3746 if ((c = memento_command_factory(n))) {
3750 } else if (n->name() == "NoteDiffCommand") {
3751 PBD::ID id (n->property("midi-source")->value());
3752 boost::shared_ptr<MidiSource> midi_source =
3753 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3755 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3757 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3760 } else if (n->name() == "SysExDiffCommand") {
3762 PBD::ID id (n->property("midi-source")->value());
3763 boost::shared_ptr<MidiSource> midi_source =
3764 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3766 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3768 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3771 } else if (n->name() == "PatchChangeDiffCommand") {
3773 PBD::ID id (n->property("midi-source")->value());
3774 boost::shared_ptr<MidiSource> midi_source =
3775 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3777 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3779 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3782 } else if (n->name() == "StatefulDiffCommand") {
3783 if ((c = stateful_diff_command_factory (n))) {
3784 ut->add_command (c);
3787 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3798 Session::config_changed (std::string p, bool ours)
3804 if (p == "seamless-loop") {
3806 } else if (p == "rf-speed") {
3808 } else if (p == "auto-loop") {
3810 } else if (p == "auto-input") {
3812 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3813 /* auto-input only makes a difference if we're rolling */
3814 set_track_monitor_input_status (!config.get_auto_input());
3817 } else if (p == "punch-in") {
3821 if ((location = _locations->auto_punch_location()) != 0) {
3823 if (config.get_punch_in ()) {
3824 replace_event (SessionEvent::PunchIn, location->start());
3826 remove_event (location->start(), SessionEvent::PunchIn);
3830 } else if (p == "punch-out") {
3834 if ((location = _locations->auto_punch_location()) != 0) {
3836 if (config.get_punch_out()) {
3837 replace_event (SessionEvent::PunchOut, location->end());
3839 clear_events (SessionEvent::PunchOut);
3843 } else if (p == "edit-mode") {
3845 Glib::Threads::Mutex::Lock lm (playlists->lock);
3847 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3848 (*i)->set_edit_mode (Config->get_edit_mode ());
3851 } else if (p == "use-video-sync") {
3853 waiting_for_sync_offset = config.get_use_video_sync();
3855 } else if (p == "mmc-control") {
3857 //poke_midi_thread ();
3859 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3861 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3863 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3865 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3867 } else if (p == "midi-control") {
3869 //poke_midi_thread ();
3871 } else if (p == "raid-path") {
3873 setup_raid_path (config.get_raid_path());
3875 } else if (p == "timecode-format") {
3879 } else if (p == "video-pullup") {
3883 } else if (p == "seamless-loop") {
3885 if (play_loop && transport_rolling()) {
3886 // to reset diskstreams etc
3887 request_play_loop (true);
3890 } else if (p == "rf-speed") {
3892 cumulative_rf_motion = 0;
3895 } else if (p == "click-sound") {
3897 setup_click_sounds (1);
3899 } else if (p == "click-emphasis-sound") {
3901 setup_click_sounds (-1);
3903 } else if (p == "clicking") {
3905 if (Config->get_clicking()) {
3906 if (_click_io && click_data) { // don't require emphasis data
3913 } else if (p == "click-gain") {
3916 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3919 } else if (p == "send-mtc") {
3921 if (Config->get_send_mtc ()) {
3922 /* mark us ready to send */
3923 next_quarter_frame_to_send = 0;
3926 } else if (p == "send-mmc") {
3928 _mmc->enable_send (Config->get_send_mmc ());
3930 } else if (p == "midi-feedback") {
3932 session_midi_feedback = Config->get_midi_feedback();
3934 } else if (p == "jack-time-master") {
3936 engine().reset_timebase ();
3938 } else if (p == "native-file-header-format") {
3940 if (!first_file_header_format_reset) {
3941 reset_native_file_format ();
3944 first_file_header_format_reset = false;
3946 } else if (p == "native-file-data-format") {
3948 if (!first_file_data_format_reset) {
3949 reset_native_file_format ();
3952 first_file_data_format_reset = false;
3954 } else if (p == "external-sync") {
3955 if (!config.get_external_sync()) {
3956 drop_sync_source ();
3958 switch_to_sync_source (Config->get_sync_source());
3960 } else if (p == "denormal-model") {
3962 } else if (p == "history-depth") {
3963 set_history_depth (Config->get_history_depth());
3964 } else if (p == "remote-model") {
3965 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3968 } else if (p == "initial-program-change") {
3970 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3973 buf[0] = MIDI::program; // channel zero by default
3974 buf[1] = (Config->get_initial_program_change() & 0x7f);
3976 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3978 } else if (p == "solo-mute-override") {
3979 // catch_up_on_solo_mute_override ();
3980 } else if (p == "listen-position" || p == "pfl-position") {
3981 listen_position_changed ();
3982 } else if (p == "solo-control-is-listen-control") {
3983 solo_control_mode_changed ();
3984 } else if (p == "solo-mute-gain") {
3985 _solo_cut_control->Changed (true, Controllable::NoGroup);
3986 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3987 last_timecode_valid = false;
3988 } else if (p == "playback-buffer-seconds") {
3989 AudioSource::allocate_working_buffers (frame_rate());
3990 } else if (p == "ltc-source-port") {
3991 reconnect_ltc_input ();
3992 } else if (p == "ltc-sink-port") {
3993 reconnect_ltc_output ();
3994 } else if (p == "timecode-generator-offset") {
3995 ltc_tx_parse_offset();
3996 } else if (p == "auto-return-target-list") {
3997 follow_playhead_priority ();
4004 Session::set_history_depth (uint32_t d)
4006 _history.set_depth (d);
4010 Session::load_diskstreams_2X (XMLNode const & node, int)
4013 XMLNodeConstIterator citer;
4015 clist = node.children();
4017 for (citer = clist.begin(); citer != clist.end(); ++citer) {
4020 /* diskstreams added automatically by DiskstreamCreated handler */
4021 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
4022 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
4023 _diskstreams_2X.push_back (dsp);
4025 error << _("Session: unknown diskstream type in XML") << endmsg;
4029 catch (failed_constructor& err) {
4030 error << _("Session: could not load diskstream via XML state") << endmsg;
4038 /** Connect things to the MMC object */
4040 Session::setup_midi_machine_control ()
4042 _mmc = new MIDI::MachineControl;
4044 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4045 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4047 if (!async_out || !async_out) {
4051 /* XXXX argh, passing raw pointers back into libmidi++ */
4053 MIDI::Port* mmc_in = async_in.get();
4054 MIDI::Port* mmc_out = async_out.get();
4056 _mmc->set_ports (mmc_in, mmc_out);
4058 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4059 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4060 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4061 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4062 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4063 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4064 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4065 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4066 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4067 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4068 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4069 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4070 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4072 /* also handle MIDI SPP because its so common */
4074 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4075 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4076 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4079 boost::shared_ptr<Controllable>
4080 Session::solo_cut_control() const
4082 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4083 controls in Ardour that currently get presented to the user in the GUI that require
4084 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4086 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4087 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4091 return _solo_cut_control;
4095 Session::save_snapshot_name (const std::string & n)
4097 /* assure Stateful::_instant_xml is loaded
4098 * add_instant_xml() only adds to existing data and defaults
4099 * to use an empty Tree otherwise
4101 instant_xml ("LastUsedSnapshot");
4103 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4104 last_used_snapshot->add_property ("name", string(n));
4105 add_instant_xml (*last_used_snapshot, false);
4109 Session::set_snapshot_name (const std::string & n)
4111 _current_snapshot_name = n;
4112 save_snapshot_name (n);
4116 Session::rename (const std::string& new_name)
4118 string legal_name = legalize_for_path (new_name);
4124 string const old_sources_root = _session_dir->sources_root();
4126 if (!_writable || (_state_of_the_state & CannotSave)) {
4127 error << _("Cannot rename read-only session.") << endmsg;
4128 return 0; // don't show "messed up" warning
4130 if (record_status() == Recording) {
4131 error << _("Cannot rename session while recording") << endmsg;
4132 return 0; // don't show "messed up" warning
4135 StateProtector stp (this);
4140 * interchange subdirectory
4144 * Backup files are left unchanged and not renamed.
4147 /* Windows requires that we close all files before attempting the
4148 * rename. This works on other platforms, but isn't necessary there.
4149 * Leave it in place for all platforms though, since it may help
4150 * catch issues that could arise if the way Source files work ever
4151 * change (since most developers are not using Windows).
4154 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4155 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4161 /* pass one: not 100% safe check that the new directory names don't
4165 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4169 /* this is a stupid hack because Glib::path_get_dirname() is
4170 * lexical-only, and so passing it /a/b/c/ gives a different
4171 * result than passing it /a/b/c ...
4174 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4175 oldstr = oldstr.substr (0, oldstr.length() - 1);
4178 string base = Glib::path_get_dirname (oldstr);
4180 newstr = Glib::build_filename (base, legal_name);
4182 cerr << "Looking for " << newstr << endl;
4184 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4185 cerr << " exists\n";
4194 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4200 /* this is a stupid hack because Glib::path_get_dirname() is
4201 * lexical-only, and so passing it /a/b/c/ gives a different
4202 * result than passing it /a/b/c ...
4205 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4206 oldstr = oldstr.substr (0, oldstr.length() - 1);
4209 string base = Glib::path_get_dirname (oldstr);
4210 newstr = Glib::build_filename (base, legal_name);
4212 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4214 cerr << "Rename " << oldstr << " => " << newstr << endl;
4215 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4216 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4217 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4221 /* Reset path in "session dirs" */
4226 /* reset primary SessionDirectory object */
4229 (*_session_dir) = newstr;
4234 /* now rename directory below session_dir/interchange */
4236 string old_interchange_dir;
4237 string new_interchange_dir;
4239 /* use newstr here because we renamed the path
4240 * (folder/directory) that used to be oldstr to newstr above
4243 v.push_back (newstr);
4244 v.push_back (interchange_dir_name);
4245 v.push_back (Glib::path_get_basename (oldstr));
4247 old_interchange_dir = Glib::build_filename (v);
4250 v.push_back (newstr);
4251 v.push_back (interchange_dir_name);
4252 v.push_back (legal_name);
4254 new_interchange_dir = Glib::build_filename (v);
4256 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4258 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4259 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4260 old_interchange_dir, new_interchange_dir,
4263 error << string_compose (_("renaming %s as %2 failed (%3)"),
4264 old_interchange_dir, new_interchange_dir,
4273 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4274 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4276 cerr << "Rename " << oldstr << " => " << newstr << endl;
4278 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4279 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4280 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4286 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4288 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4289 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4291 cerr << "Rename " << oldstr << " => " << newstr << endl;
4293 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4294 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4295 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4300 /* remove old name from recent sessions */
4301 remove_recent_sessions (_path);
4304 /* update file source paths */
4306 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4307 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4309 string p = fs->path ();
4310 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4312 SourceFactory::setup_peakfile(i->second, true);
4316 set_snapshot_name (new_name);
4321 /* save state again to get everything just right */
4323 save_state (_current_snapshot_name);
4325 /* add to recent sessions */
4327 store_recent_sessions (new_name, _path);
4333 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4335 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4339 if (!tree.read (xmlpath)) {
4347 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4350 bool found_sr = false;
4351 bool found_data_format = false;
4353 if (get_session_info_from_path (tree, xmlpath)) {
4359 XMLProperty const * prop;
4360 XMLNode const * root (tree.root());
4362 if ((prop = root->property (X_("sample-rate"))) != 0) {
4363 sample_rate = atoi (prop->value());
4367 const XMLNodeList& children (root->children());
4368 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4369 const XMLNode* child = *c;
4370 if (child->name() == "Config") {
4371 const XMLNodeList& options (child->children());
4372 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4373 XMLNode const * option = *oc;
4374 XMLProperty const * name = option->property("name");
4380 if (name->value() == "native-file-data-format") {
4381 XMLProperty const * value = option->property ("value");
4383 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4385 found_data_format = true;
4391 if (found_data_format) {
4396 return !(found_sr && found_data_format); // zero if they are both found
4400 Session::get_snapshot_from_instant (const std::string& session_dir)
4402 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4404 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4409 if (!tree.read (instant_xml_path)) {
4413 XMLProperty const * prop;
4414 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4415 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4416 return prop->value();
4422 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4423 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4426 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4430 SourcePathMap source_path_map;
4432 boost::shared_ptr<AudioFileSource> afs;
4437 Glib::Threads::Mutex::Lock lm (source_lock);
4439 cerr << " total sources = " << sources.size();
4441 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4442 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4448 if (fs->within_session()) {
4452 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4453 source_path_map[fs->path()].push_back (fs);
4455 SeveralFileSources v;
4457 source_path_map.insert (make_pair (fs->path(), v));
4463 cerr << " fsources = " << total << endl;
4465 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4467 /* tell caller where we are */
4469 string old_path = i->first;
4471 callback (n, total, old_path);
4473 cerr << old_path << endl;
4477 switch (i->second.front()->type()) {
4478 case DataType::AUDIO:
4479 new_path = new_audio_source_path_for_embedded (old_path);
4482 case DataType::MIDI:
4483 /* XXX not implemented yet */
4487 if (new_path.empty()) {
4491 cerr << "Move " << old_path << " => " << new_path << endl;
4493 if (!copy_file (old_path, new_path)) {
4494 cerr << "failed !\n";
4498 /* make sure we stop looking in the external
4499 dir/folder. Remember, this is an all-or-nothing
4500 operations, it doesn't merge just some files.
4502 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4504 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4505 (*f)->set_path (new_path);
4510 save_state ("", false, false);
4516 bool accept_all_files (string const &, void *)
4522 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4524 /* 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.
4529 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4531 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4533 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4535 v.push_back (new_session_folder); /* full path */
4536 v.push_back (interchange_dir_name);
4537 v.push_back (new_session_path); /* just one directory/folder */
4538 v.push_back (typedir);
4539 v.push_back (Glib::path_get_basename (old_path));
4541 return Glib::build_filename (v);
4545 Session::save_as (SaveAs& saveas)
4547 vector<string> files;
4548 string current_folder = Glib::path_get_dirname (_path);
4549 string new_folder = legalize_for_path (saveas.new_name);
4550 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4551 int64_t total_bytes = 0;
4555 int32_t internal_file_cnt = 0;
4557 vector<string> do_not_copy_extensions;
4558 do_not_copy_extensions.push_back (statefile_suffix);
4559 do_not_copy_extensions.push_back (pending_suffix);
4560 do_not_copy_extensions.push_back (backup_suffix);
4561 do_not_copy_extensions.push_back (temp_suffix);
4562 do_not_copy_extensions.push_back (history_suffix);
4564 /* get total size */
4566 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4568 /* need to clear this because
4569 * find_files_matching_filter() is cumulative
4574 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4576 all += files.size();
4578 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4580 g_stat ((*i).c_str(), &gsb);
4581 total_bytes += gsb.st_size;
4585 /* save old values so we can switch back if we are not switching to the new session */
4587 string old_path = _path;
4588 string old_name = _name;
4589 string old_snapshot = _current_snapshot_name;
4590 string old_sd = _session_dir->root_path();
4591 vector<string> old_search_path[DataType::num_types];
4592 string old_config_search_path[DataType::num_types];
4594 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4595 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4596 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4597 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4599 /* switch session directory */
4601 (*_session_dir) = to_dir;
4603 /* create new tree */
4605 if (!_session_dir->create()) {
4606 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4611 /* copy all relevant files. Find each location in session_dirs,
4612 * and copy files from there to target.
4615 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4617 /* need to clear this because
4618 * find_files_matching_filter() is cumulative
4623 const size_t prefix_len = (*sd).path.size();
4625 /* Work just on the files within this session dir */
4627 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4629 /* add dir separator to protect against collisions with
4630 * track names (e.g. track named "audiofiles" or
4634 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4635 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4636 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4638 /* copy all the files. Handling is different for media files
4639 than others because of the *silly* subtree we have below the interchange
4640 folder. That really was a bad idea, but I'm not fixing it as part of
4641 implementing ::save_as().
4644 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4646 std::string from = *i;
4649 string filename = Glib::path_get_basename (from);
4650 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4651 if (filename == ".DS_STORE") {
4656 if (from.find (audiofile_dir_string) != string::npos) {
4658 /* audio file: only copy if asked */
4660 if (saveas.include_media && saveas.copy_media) {
4662 string to = make_new_media_path (*i, to_dir, new_folder);
4664 info << "media file copying from " << from << " to " << to << endmsg;
4666 if (!copy_file (from, to)) {
4667 throw Glib::FileError (Glib::FileError::IO_ERROR,
4668 string_compose(_("\ncopying \"%1\" failed !"), from));
4672 /* we found media files inside the session folder */
4674 internal_file_cnt++;
4676 } else if (from.find (midifile_dir_string) != string::npos) {
4678 /* midi file: always copy unless
4679 * creating an empty new session
4682 if (saveas.include_media) {
4684 string to = make_new_media_path (*i, to_dir, new_folder);
4686 info << "media file copying from " << from << " to " << to << endmsg;
4688 if (!copy_file (from, to)) {
4689 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4693 /* we found media files inside the session folder */
4695 internal_file_cnt++;
4697 } else if (from.find (analysis_dir_string) != string::npos) {
4699 /* make sure analysis dir exists in
4700 * new session folder, but we're not
4701 * copying analysis files here, see
4705 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4710 /* normal non-media file. Don't copy state, history, etc.
4713 bool do_copy = true;
4715 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4716 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4717 /* end of filename matches extension, do not copy file */
4723 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4724 /* don't copy peakfiles if
4725 * we're not copying media
4731 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4733 info << "attempting to make directory/folder " << to << endmsg;
4735 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4736 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4739 info << "attempting to copy " << from << " to " << to << endmsg;
4741 if (!copy_file (from, to)) {
4742 throw Glib::FileError (Glib::FileError::IO_ERROR,
4743 string_compose(_("\ncopying \"%1\" failed !"), from));
4748 /* measure file size even if we're not going to copy so that our Progress
4749 signals are correct, since we included these do-not-copy files
4750 in the computation of the total size and file count.
4754 g_stat (from.c_str(), &gsb);
4755 copied += gsb.st_size;
4758 double fraction = (double) copied / total_bytes;
4760 bool keep_going = true;
4762 if (saveas.copy_media) {
4764 /* no need or expectation of this if
4765 * media is not being copied, because
4766 * it will be fast(ish).
4769 /* tell someone "X percent, file M of N"; M is one-based */
4771 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4779 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4785 /* copy optional folders, if any */
4787 string old = plugins_dir ();
4788 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4789 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4790 copy_files (old, newdir);
4793 old = externals_dir ();
4794 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4795 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4796 copy_files (old, newdir);
4799 old = automation_dir ();
4800 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4801 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4802 copy_files (old, newdir);
4805 if (saveas.include_media) {
4807 if (saveas.copy_media) {
4808 #ifndef PLATFORM_WINDOWS
4809 /* There are problems with analysis files on
4810 * Windows, because they used a colon in their
4811 * names as late as 4.0. Colons are not legal
4812 * under Windows even if NTFS allows them.
4814 * This is a tricky problem to solve so for
4815 * just don't copy these files. They will be
4816 * regenerated as-needed anyway, subject to the
4817 * existing issue that the filenames will be
4818 * rejected by Windows, which is a separate
4819 * problem (though related).
4822 /* only needed if we are copying media, since the
4823 * analysis data refers to media data
4826 old = analysis_dir ();
4827 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4828 string newdir = Glib::build_filename (to_dir, "analysis");
4829 copy_files (old, newdir);
4831 #endif /* PLATFORM_WINDOWS */
4837 set_snapshot_name (saveas.new_name);
4838 _name = saveas.new_name;
4840 if (saveas.include_media && !saveas.copy_media) {
4842 /* reset search paths of the new session (which we're pretending to be right now) to
4843 include the original session search path, so we can still find all audio.
4846 if (internal_file_cnt) {
4847 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4848 ensure_search_path_includes (*s, DataType::AUDIO);
4849 cerr << "be sure to include " << *s << " for audio" << endl;
4852 /* we do not do this for MIDI because we copy
4853 all MIDI files if saveas.include_media is
4859 bool was_dirty = dirty ();
4861 save_state ("", false, false, !saveas.include_media);
4862 save_default_options ();
4864 if (saveas.copy_media && saveas.copy_external) {
4865 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4866 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4870 saveas.final_session_folder_name = _path;
4872 store_recent_sessions (_name, _path);
4874 if (!saveas.switch_to) {
4876 /* switch back to the way things were */
4880 set_snapshot_name (old_snapshot);
4882 (*_session_dir) = old_sd;
4888 if (internal_file_cnt) {
4889 /* reset these to their original values */
4890 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4891 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4896 /* prune session dirs, and update disk space statistics
4901 session_dirs.clear ();
4902 session_dirs.push_back (sp);
4903 refresh_disk_space ();
4905 /* ensure that all existing tracks reset their current capture source paths
4907 reset_write_sources (true, true);
4909 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4910 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4913 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4914 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4920 if (fs->within_session()) {
4921 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4922 fs->set_path (newpath);
4927 } catch (Glib::FileError& e) {
4929 saveas.failure_message = e.what();
4931 /* recursively remove all the directories */
4933 remove_directory (to_dir);
4941 saveas.failure_message = _("unknown reason");
4943 /* recursively remove all the directories */
4945 remove_directory (to_dir);
4955 static void set_progress (Progress* p, size_t n, size_t t)
4957 p->set_progress (float (n) / float(t));
4961 Session::archive_session (const std::string& dest,
4962 const std::string& name,
4963 ArchiveEncode compress_audio,
4964 bool only_used_sources,
4967 if (dest.empty () || name.empty ()) {
4971 /* save current values */
4972 bool was_dirty = dirty ();
4973 string old_path = _path;
4974 string old_name = _name;
4975 string old_snapshot = _current_snapshot_name;
4976 string old_sd = _session_dir->root_path();
4977 string old_config_search_path[DataType::num_types];
4978 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4979 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4981 /* ensure that session-path is included in search-path */
4983 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4984 if ((*sd).path == old_path) {
4992 /* create temporary dir to save session to */
4993 #ifdef PLATFORM_WINDOWS
4994 char tmp[256] = "C:\\TEMP\\";
4995 GetTempPath (sizeof (tmp), tmp);
4997 char const* tmp = getenv("TMPDIR");
5002 if ((strlen (tmp) + 21) > 1024) {
5007 strcpy (tmptpl, tmp);
5008 strcat (tmptpl, "ardourarchive-XXXXXX");
5009 char* tmpdir = g_mkdtemp (tmptpl);
5015 std::string to_dir = std::string (tmpdir);
5017 /* switch session directory temporarily */
5018 (*_session_dir) = to_dir;
5020 if (!_session_dir->create()) {
5021 (*_session_dir) = old_sd;
5022 remove_directory (to_dir);
5026 /* prepare archive */
5027 string archive = Glib::build_filename (dest, name + ".tar.xz");
5029 PBD::ScopedConnectionList progress_connection;
5030 PBD::FileArchive ar (archive);
5032 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5035 /* collect files to archive */
5036 std::map<string,string> filemap;
5038 vector<string> do_not_copy_extensions;
5039 do_not_copy_extensions.push_back (statefile_suffix);
5040 do_not_copy_extensions.push_back (pending_suffix);
5041 do_not_copy_extensions.push_back (backup_suffix);
5042 do_not_copy_extensions.push_back (temp_suffix);
5043 do_not_copy_extensions.push_back (history_suffix);
5045 vector<string> blacklist_dirs;
5046 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5047 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5048 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5049 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5050 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5051 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5053 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5055 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5056 if (only_used_sources) {
5057 playlists->sync_all_regions_with_regions ();
5058 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5061 // collect audio sources for this session, calc total size for encoding
5062 // add option to only include *used* sources (see Session::cleanup_sources)
5063 size_t total_size = 0;
5065 Glib::Threads::Mutex::Lock lm (source_lock);
5066 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5067 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5068 if (!afs || afs->readable_length () == 0) {
5072 if (only_used_sources) {
5076 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5081 std::string from = afs->path();
5083 if (compress_audio != NO_ENCODE) {
5084 total_size += afs->readable_length ();
5086 if (afs->within_session()) {
5087 filemap[from] = make_new_media_path (from, name, name);
5089 filemap[from] = make_new_media_path (from, name, name);
5090 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5097 if (compress_audio != NO_ENCODE) {
5099 progress->set_progress (2); // set to "encoding"
5100 progress->set_progress (0);
5103 Glib::Threads::Mutex::Lock lm (source_lock);
5104 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5105 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5106 if (!afs || afs->readable_length () == 0) {
5110 if (only_used_sources) {
5114 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5119 orig_sources[afs] = afs->path();
5121 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5122 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5123 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5126 progress->descend ((float)afs->readable_length () / total_size);
5130 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5131 afs->replace_file (new_path);
5134 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5138 progress->ascend ();
5144 progress->set_progress (-1); // set to "archiving"
5145 progress->set_progress (0);
5148 /* index files relevant for this session */
5149 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5150 vector<string> files;
5152 size_t prefix_len = (*sd).path.size();
5153 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5157 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5159 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5160 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5161 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5163 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5164 std::string from = *i;
5167 string filename = Glib::path_get_basename (from);
5168 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5169 if (filename == ".DS_STORE") {
5174 if (from.find (audiofile_dir_string) != string::npos) {
5176 } else if (from.find (midifile_dir_string) != string::npos) {
5177 filemap[from] = make_new_media_path (from, name, name);
5178 } else if (from.find (videofile_dir_string) != string::npos) {
5179 filemap[from] = make_new_media_path (from, name, name);
5181 bool do_copy = true;
5182 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5183 if (from.find (*v) != string::npos) {
5188 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5189 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5196 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5202 /* write session file */
5204 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5206 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5208 save_default_options ();
5210 size_t prefix_len = _path.size();
5211 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5215 /* collect session-state files */
5216 vector<string> files;
5217 do_not_copy_extensions.clear ();
5218 do_not_copy_extensions.push_back (history_suffix);
5220 blacklist_dirs.clear ();
5221 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5223 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5224 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5225 std::string from = *i;
5226 bool do_copy = true;
5227 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5228 if (from.find (*v) != string::npos) {
5233 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5234 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5240 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5244 /* restore original values */
5247 set_snapshot_name (old_snapshot);
5248 (*_session_dir) = old_sd;
5252 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5253 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5255 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5256 i->first->replace_file (i->second);
5259 int rv = ar.create (filemap);
5260 remove_directory (to_dir);
5266 Session::undo (uint32_t n)
5268 if (actively_recording()) {
5276 Session::redo (uint32_t n)
5278 if (actively_recording()) {