2 Copyright (C) 1999-2013 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "libardour-config.h"
30 #include <cstdio> /* snprintf(3) ... grrr */
42 #if defined(__APPLE__) || defined(__FreeBSD__)
43 #include <sys/param.h>
44 #include <sys/mount.h>
47 #ifdef HAVE_SYS_STATVFS_H
48 #include <sys/statvfs.h>
52 #include "pbd/gstdio_compat.h"
55 #include <glibmm/threads.h>
56 #include <glibmm/fileutils.h>
58 #include <boost/algorithm/string.hpp>
60 #include "midi++/mmc.h"
61 #include "midi++/port.h"
63 #include "evoral/SMF.hpp"
65 #include "pbd/basename.h"
66 #include "pbd/debug.h"
67 #include "pbd/enumwriter.h"
68 #include "pbd/error.h"
69 #include "pbd/file_archive.h"
70 #include "pbd/file_utils.h"
71 #include "pbd/pathexpand.h"
72 #include "pbd/pthread_utils.h"
73 #include "pbd/stacktrace.h"
74 #include "pbd/convert.h"
75 #include "pbd/localtime_r.h"
76 #include "pbd/unwind.h"
78 #include "ardour/amp.h"
79 #include "ardour/async_midi_port.h"
80 #include "ardour/audio_diskstream.h"
81 #include "ardour/audio_track.h"
82 #include "ardour/audioengine.h"
83 #include "ardour/audiofilesource.h"
84 #include "ardour/audioregion.h"
85 #include "ardour/auditioner.h"
86 #include "ardour/automation_control.h"
87 #include "ardour/boost_debug.h"
88 #include "ardour/butler.h"
89 #include "ardour/controllable_descriptor.h"
90 #include "ardour/control_protocol_manager.h"
91 #include "ardour/directory_names.h"
92 #include "ardour/filename_extensions.h"
93 #include "ardour/graph.h"
94 #include "ardour/location.h"
95 #include "ardour/lv2_plugin.h"
96 #include "ardour/midi_model.h"
97 #include "ardour/midi_patch_manager.h"
98 #include "ardour/midi_region.h"
99 #include "ardour/midi_scene_changer.h"
100 #include "ardour/midi_source.h"
101 #include "ardour/midi_track.h"
102 #include "ardour/pannable.h"
103 #include "ardour/playlist_factory.h"
104 #include "ardour/playlist_source.h"
105 #include "ardour/port.h"
106 #include "ardour/processor.h"
107 #include "ardour/progress.h"
108 #include "ardour/profile.h"
109 #include "ardour/proxy_controllable.h"
110 #include "ardour/recent_sessions.h"
111 #include "ardour/region_factory.h"
112 #include "ardour/revision.h"
113 #include "ardour/route_group.h"
114 #include "ardour/send.h"
115 #include "ardour/session.h"
116 #include "ardour/session_directory.h"
117 #include "ardour/session_metadata.h"
118 #include "ardour/session_playlists.h"
119 #include "ardour/session_state_utils.h"
120 #include "ardour/silentfilesource.h"
121 #include "ardour/sndfilesource.h"
122 #include "ardour/source_factory.h"
123 #include "ardour/speakers.h"
124 #include "ardour/template_utils.h"
125 #include "ardour/tempo.h"
126 #include "ardour/ticker.h"
127 #include "ardour/user_bundle.h"
128 #include "ardour/vca.h"
129 #include "ardour/vca_manager.h"
131 #include "control_protocol/control_protocol.h"
133 #include "LuaBridge/LuaBridge.h"
135 #include "pbd/i18n.h"
139 using namespace ARDOUR;
142 #define DEBUG_UNDO_HISTORY(msg) DEBUG_TRACE (PBD::DEBUG::UndoHistory, string_compose ("%1: %2\n", __LINE__, msg));
145 Session::pre_engine_init (string fullpath)
147 if (fullpath.empty()) {
149 throw failed_constructor();
152 /* discover canonical fullpath */
154 _path = canonical_path(fullpath);
157 if (Profile->get_trx() ) {
158 // Waves TracksLive has a usecase of session replacement with a new one.
159 // We should check session state file (<session_name>.ardour) existance
160 // to determine if the session is new or not
162 string full_session_name = Glib::build_filename( fullpath, _name );
163 full_session_name += statefile_suffix;
165 _is_new = !Glib::file_test (full_session_name, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
167 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
170 /* finish initialization that can't be done in a normal C++ constructor
174 timerclear (&last_mmc_step);
175 g_atomic_int_set (&processing_prohibited, 0);
176 g_atomic_int_set (&_record_status, Disabled);
177 g_atomic_int_set (&_playback_load, 100);
178 g_atomic_int_set (&_capture_load, 100);
180 _all_route_group->set_active (true, this);
181 interpolation.add_channel_to (0, 0);
183 if (config.get_use_video_sync()) {
184 waiting_for_sync_offset = true;
186 waiting_for_sync_offset = false;
189 last_rr_session_dir = session_dirs.begin();
191 set_history_depth (Config->get_history_depth());
193 /* default: assume simple stereo speaker configuration */
195 _speakers->setup_default_speakers (2);
197 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
198 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
199 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
200 add_controllable (_solo_cut_control);
202 /* These are all static "per-class" signals */
204 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
205 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
206 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
207 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
208 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
210 /* stop IO objects from doing stuff until we're ready for them */
212 Delivery::disable_panners ();
213 IO::disable_connecting ();
217 Session::post_engine_init ()
219 BootMessage (_("Set block size and sample rate"));
221 set_block_size (_engine.samples_per_cycle());
222 set_frame_rate (_engine.sample_rate());
224 BootMessage (_("Using configuration"));
226 _midi_ports = new MidiPortManager;
228 MIDISceneChanger* msc;
230 _scene_changer = msc = new MIDISceneChanger (*this);
231 msc->set_input_port (boost::dynamic_pointer_cast<MidiPort>(scene_input_port()));
232 msc->set_output_port (boost::dynamic_pointer_cast<MidiPort>(scene_output_port()));
234 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
235 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_input_port())->set_timer (timer_func);
237 setup_midi_machine_control ();
239 if (_butler->start_thread()) {
240 error << _("Butler did not start") << endmsg;
244 if (start_midi_thread ()) {
245 error << _("MIDI I/O thread did not start") << endmsg;
249 setup_click_sounds (0);
250 setup_midi_control ();
252 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
253 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
256 /* tempo map requires sample rate knowledge */
259 _tempo_map = new TempoMap (_current_frame_rate);
260 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
261 _tempo_map->MetricPositionChanged.connect_same_thread (*this, boost::bind (&Session::gui_tempo_map_changed, this));
263 /* MidiClock requires a tempo map */
266 midi_clock = new MidiClockTicker ();
267 midi_clock->set_session (this);
269 /* crossfades require sample rate knowledge */
271 SndFileSource::setup_standard_crossfades (*this, frame_rate());
272 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
274 AudioDiskstream::allocate_working_buffers();
275 refresh_disk_space ();
277 /* we're finally ready to call set_state() ... all objects have
278 * been created, the engine is running.
282 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
283 error << _("Could not set session state from XML") << endmsg;
287 // set_state() will call setup_raid_path(), but if it's a new session we need
288 // to call setup_raid_path() here.
289 setup_raid_path (_path);
294 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
295 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
297 Config->map_parameters (ff);
298 config.map_parameters (ft);
299 _butler->map_parameters ();
301 /* Reset all panners */
303 Delivery::reset_panners ();
305 /* this will cause the CPM to instantiate any protocols that are in use
306 * (or mandatory), which will pass it this Session, and then call
307 * set_state() on each instantiated protocol to match stored state.
310 ControlProtocolManager::instance().set_session (this);
312 /* This must be done after the ControlProtocolManager set_session above,
313 as it will set states for ports which the ControlProtocolManager creates.
316 // XXX set state of MIDI::Port's
317 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
319 /* And this must be done after the MIDI::Manager::set_port_states as
320 * it will try to make connections whose details are loaded by set_port_states.
325 /* Let control protocols know that we are now all connected, so they
326 * could start talking to surfaces if they want to.
329 ControlProtocolManager::instance().midi_connectivity_established ();
331 if (_is_new && !no_auto_connect()) {
332 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
333 auto_connect_master_bus ();
336 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
338 /* update latencies */
340 initialize_latencies ();
342 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
343 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
344 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
346 } catch (AudioEngine::PortRegistrationFailure& err) {
347 /* handle this one in a different way than all others, so that its clear what happened */
348 error << err.what() << endmsg;
350 } catch (std::exception const & e) {
351 error << _("Unexpected exception during session setup: ") << e.what() << endmsg;
354 error << _("Unknown exception during session setup") << endmsg;
358 BootMessage (_("Reset Remote Controls"));
360 // send_full_time_code (0);
361 _engine.transport_locate (0);
363 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
364 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
366 MIDI::Name::MidiPatchManager::instance().add_search_path (session_directory().midi_patch_path() );
369 /* initial program change will be delivered later; see ::config_changed() */
371 _state_of_the_state = Clean;
373 Port::set_connecting_blocked (false);
375 DirtyChanged (); /* EMIT SIGNAL */
379 } else if (state_was_pending) {
381 remove_pending_capture_state ();
382 state_was_pending = false;
385 /* Now, finally, we can fill the playback buffers */
387 BootMessage (_("Filling playback buffers"));
389 boost::shared_ptr<RouteList> rl = routes.reader();
390 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
391 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
392 if (trk && !trk->hidden()) {
393 trk->seek (_transport_frame, true);
401 Session::session_loaded ()
405 _state_of_the_state = Clean;
407 DirtyChanged (); /* EMIT SIGNAL */
411 } else if (state_was_pending) {
413 remove_pending_capture_state ();
414 state_was_pending = false;
417 /* Now, finally, we can fill the playback buffers */
419 BootMessage (_("Filling playback buffers"));
420 force_locate (_transport_frame, false);
424 Session::raid_path () const
426 Searchpath raid_search_path;
428 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
429 raid_search_path += (*i).path;
432 return raid_search_path.to_string ();
436 Session::setup_raid_path (string path)
445 session_dirs.clear ();
447 Searchpath search_path(path);
448 Searchpath sound_search_path;
449 Searchpath midi_search_path;
451 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
453 sp.blocks = 0; // not needed
454 session_dirs.push_back (sp);
456 SessionDirectory sdir(sp.path);
458 sound_search_path += sdir.sound_path ();
459 midi_search_path += sdir.midi_path ();
462 // reset the round-robin soundfile path thingie
463 last_rr_session_dir = session_dirs.begin();
467 Session::path_is_within_session (const std::string& path)
469 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
470 if (PBD::path_is_within (i->path, path)) {
478 Session::ensure_subdirs ()
482 dir = session_directory().peak_path();
484 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
485 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
489 dir = session_directory().sound_path();
491 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
492 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
496 dir = session_directory().midi_path();
498 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
499 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
503 dir = session_directory().dead_path();
505 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
506 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
510 dir = session_directory().export_path();
512 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
513 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
517 dir = analysis_dir ();
519 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
520 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
524 dir = plugins_dir ();
526 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
527 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
531 dir = externals_dir ();
533 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
534 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
541 /** @param session_template directory containing session template, or empty.
542 * Caller must not hold process lock.
545 Session::create (const string& session_template, BusProfile* bus_profile)
547 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
548 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
552 if (ensure_subdirs ()) {
556 _writable = exists_and_writable (_path);
558 if (!session_template.empty()) {
559 string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
561 FILE* in = g_fopen (in_path.c_str(), "rb");
564 /* no need to call legalize_for_path() since the string
565 * in session_template is already a legal path name
567 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
569 FILE* out = g_fopen (out_path.c_str(), "wb");
573 stringstream new_session;
576 size_t charsRead = fread (buf, sizeof(char), 1024, in);
579 error << string_compose (_("Error reading session template file %1 (%2)"), in_path, strerror (errno)) << endmsg;
584 if (charsRead == 0) {
587 new_session.write (buf, charsRead);
591 string file_contents = new_session.str();
592 size_t writeSize = file_contents.length();
593 if (fwrite (file_contents.c_str(), sizeof(char), writeSize, out) != writeSize) {
594 error << string_compose (_("Error writing session template file %1 (%2)"), out_path, strerror (errno)) << endmsg;
602 if (!ARDOUR::Profile->get_trx()) {
603 /* Copy plugin state files from template to new session */
604 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
605 copy_recurse (template_plugins, plugins_dir ());
611 error << string_compose (_("Could not open %1 for writing session template"), out_path)
618 error << string_compose (_("Could not open session template %1 for reading"), in_path)
625 if (Profile->get_trx()) {
627 /* set initial start + end point : ARDOUR::Session::session_end_shift long.
628 Remember that this is a brand new session. Sessions
629 loaded from saved state will get this range from the saved state.
632 set_session_range_location (0, 0);
634 /* Initial loop location, from absolute zero, length 10 seconds */
636 Location* loc = new Location (*this, 0, 10.0 * _engine.sample_rate(), _("Loop"), Location::IsAutoLoop);
637 _locations->add (loc, true);
638 set_auto_loop_location (loc);
641 _state_of_the_state = Clean;
643 /* set up Master Out and Monitor Out if necessary */
648 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
650 // Waves Tracks: always create master bus for Tracks
651 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
652 boost::shared_ptr<Route> r (new Route (*this, _("Master"), PresentationInfo::MasterOut, DataType::AUDIO));
660 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
661 r->input()->ensure_io (count, false, this);
662 r->output()->ensure_io (count, false, this);
668 /* prohibit auto-connect to master, because there isn't one */
669 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
673 add_routes (rl, false, false, false, PresentationInfo::max_order);
676 // Waves Tracks: Skip this. Always use autoconnection for Tracks
677 if (!ARDOUR::Profile->get_trx()) {
679 /* this allows the user to override settings with an environment variable.
682 if (no_auto_connect()) {
683 bus_profile->input_ac = AutoConnectOption (0);
684 bus_profile->output_ac = AutoConnectOption (0);
687 Config->set_input_auto_connect (bus_profile->input_ac);
688 Config->set_output_auto_connect (bus_profile->output_ac);
692 if (Config->get_use_monitor_bus() && bus_profile) {
693 add_monitor_section ();
700 Session::maybe_write_autosave()
702 if (dirty() && record_status() != Recording) {
703 save_state("", true);
708 Session::remove_pending_capture_state ()
710 std::string pending_state_file_path(_session_dir->root_path());
712 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
714 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
716 if (g_remove (pending_state_file_path.c_str()) != 0) {
717 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
718 pending_state_file_path, g_strerror (errno)) << endmsg;
722 /** Rename a state file.
723 * @param old_name Old snapshot name.
724 * @param new_name New snapshot name.
727 Session::rename_state (string old_name, string new_name)
729 if (old_name == _current_snapshot_name || old_name == _name) {
730 /* refuse to rename the current snapshot or the "main" one */
734 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
735 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
737 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
738 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
740 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
741 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
742 old_name, new_name, g_strerror(errno)) << endmsg;
746 /** Remove a state file.
747 * @param snapshot_name Snapshot name.
750 Session::remove_state (string snapshot_name)
752 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
753 // refuse to remove the current snapshot or the "main" one
757 std::string xml_path(_session_dir->root_path());
759 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
761 if (!create_backup_file (xml_path)) {
762 // don't remove it if a backup can't be made
763 // create_backup_file will log the error.
768 if (g_remove (xml_path.c_str()) != 0) {
769 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
770 xml_path, g_strerror (errno)) << endmsg;
774 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
776 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
778 DEBUG_TRACE (DEBUG::Locale, string_compose ("Session::save_state locale '%1'\n", setlocale (LC_NUMERIC, NULL)));
781 std::string xml_path(_session_dir->root_path());
783 /* prevent concurrent saves from different threads */
785 Glib::Threads::Mutex::Lock lm (save_state_lock);
787 if (!_writable || (_state_of_the_state & CannotSave)) {
791 if (g_atomic_int_get(&_suspend_save)) {
795 _save_queued = false;
797 if (!_engine.connected ()) {
798 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
805 const int64_t save_start_time = g_get_monotonic_time();
808 /* tell sources we're saving first, in case they write out to a new file
809 * which should be saved with the state rather than the old one */
810 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
812 i->second->session_saved();
813 } catch (Evoral::SMF::FileError& e) {
814 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
818 SessionSaveUnderway (); /* EMIT SIGNAL */
820 bool mark_as_clean = true;
822 if (!snapshot_name.empty() && !switch_to_snapshot) {
823 mark_as_clean = false;
827 mark_as_clean = false;
828 tree.set_root (&get_template());
830 tree.set_root (&get_state());
833 if (snapshot_name.empty()) {
834 snapshot_name = _current_snapshot_name;
835 } else if (switch_to_snapshot) {
836 set_snapshot_name (snapshot_name);
839 assert (!snapshot_name.empty());
843 /* proper save: use statefile_suffix (.ardour in English) */
845 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
847 /* make a backup copy of the old file */
849 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
850 // create_backup_file will log the error
856 /* pending save: use pending_suffix (.pending in English) */
857 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
860 std::string tmp_path(_session_dir->root_path());
861 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
863 cerr << "actually writing state to " << tmp_path << endl;
865 if (!tree.write (tmp_path)) {
866 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
867 if (g_remove (tmp_path.c_str()) != 0) {
868 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
869 tmp_path, g_strerror (errno)) << endmsg;
875 cerr << "renaming state to " << xml_path << endl;
877 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
878 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
879 tmp_path, xml_path, g_strerror(errno)) << endmsg;
880 if (g_remove (tmp_path.c_str()) != 0) {
881 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
882 tmp_path, g_strerror (errno)) << endmsg;
890 save_history (snapshot_name);
893 bool was_dirty = dirty();
895 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
898 DirtyChanged (); /* EMIT SIGNAL */
902 StateSaved (snapshot_name); /* EMIT SIGNAL */
906 const int64_t elapsed_time_us = g_get_monotonic_time() - save_start_time;
907 cerr << "saved state in " << fixed << setprecision (1) << elapsed_time_us / 1000. << " ms\n";
913 Session::restore_state (string snapshot_name)
915 if (load_state (snapshot_name) == 0) {
916 set_state (*state_tree->root(), Stateful::loading_state_version);
923 Session::load_state (string snapshot_name)
928 state_was_pending = false;
930 /* check for leftover pending state from a crashed capture attempt */
932 std::string xmlpath(_session_dir->root_path());
933 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
935 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
937 /* there is pending state from a crashed capture attempt */
939 boost::optional<int> r = AskAboutPendingState();
940 if (r.get_value_or (1)) {
941 state_was_pending = true;
945 if (!state_was_pending) {
946 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
949 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
950 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
951 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
952 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
957 state_tree = new XMLTree;
961 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
963 if (!state_tree->read (xmlpath)) {
964 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
970 XMLNode const & root (*state_tree->root());
972 if (root.name() != X_("Session")) {
973 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
979 XMLProperty const * prop;
981 if ((prop = root.property ("version")) == 0) {
982 /* no version implies very old version of Ardour */
983 Stateful::loading_state_version = 1000;
985 if (prop->value().find ('.') != string::npos) {
986 /* old school version format */
987 if (prop->value()[0] == '2') {
988 Stateful::loading_state_version = 2000;
990 Stateful::loading_state_version = 3000;
993 Stateful::loading_state_version = atoi (prop->value());
997 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
999 std::string backup_path(_session_dir->root_path());
1000 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
1001 backup_path = Glib::build_filename (backup_path, backup_filename);
1003 // only create a backup for a given statefile version once
1005 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
1007 VersionMismatch (xmlpath, backup_path);
1009 if (!copy_file (xmlpath, backup_path)) {;
1015 save_snapshot_name (snapshot_name);
1021 Session::load_options (const XMLNode& node)
1024 config.set_variables (node);
1029 Session::save_default_options ()
1031 return config.save_state();
1035 Session::get_state()
1041 Session::get_template()
1043 /* if we don't disable rec-enable, diskstreams
1044 will believe they need to store their capture
1045 sources in their state node.
1048 disable_record (false);
1050 return state(false);
1054 Session::state (bool full_state)
1057 XMLNode* node = new XMLNode("Session");
1061 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
1062 node->add_property("version", buf);
1064 child = node->add_child ("ProgramVersion");
1065 child->add_property("created-with", created_with);
1067 std::string modified_with = string_compose ("%1 %2", PROGRAM_NAME, revision);
1068 child->add_property("modified-with", modified_with);
1070 /* store configuration settings */
1074 node->add_property ("name", _name);
1075 snprintf (buf, sizeof (buf), "%" PRId64, _base_frame_rate);
1076 node->add_property ("sample-rate", buf);
1078 if (session_dirs.size() > 1) {
1082 vector<space_and_path>::iterator i = session_dirs.begin();
1083 vector<space_and_path>::iterator next;
1085 ++i; /* skip the first one */
1089 while (i != session_dirs.end()) {
1093 if (next != session_dirs.end()) {
1094 p += G_SEARCHPATH_SEPARATOR;
1103 child = node->add_child ("Path");
1104 child->add_content (p);
1108 node->add_property ("end-is-free", _session_range_end_is_free ? X_("yes") : X_("no"));
1110 /* save the ID counter */
1112 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1113 node->add_property ("id-counter", buf);
1115 snprintf (buf, sizeof (buf), "%u", name_id_counter ());
1116 node->add_property ("name-counter", buf);
1118 /* save the event ID counter */
1120 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1121 node->add_property ("event-counter", buf);
1123 /* save the VCA counter */
1125 snprintf (buf, sizeof (buf), "%" PRIu32, VCA::get_next_vca_number());
1126 node->add_property ("vca-counter", buf);
1128 /* various options */
1130 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1131 if (!midi_port_nodes.empty()) {
1132 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1133 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1134 midi_port_stuff->add_child_nocopy (**n);
1136 node->add_child_nocopy (*midi_port_stuff);
1139 node->add_child_nocopy (config.get_variables ());
1141 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1143 child = node->add_child ("Sources");
1146 Glib::Threads::Mutex::Lock sl (source_lock);
1148 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1150 /* Don't save information about non-file Sources, or
1151 * about non-destructive file sources that are empty
1152 * and unused by any regions.
1155 boost::shared_ptr<FileSource> fs;
1157 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1159 if (!fs->destructive()) {
1160 if (fs->empty() && !fs->used()) {
1165 child->add_child_nocopy (siter->second->get_state());
1170 child = node->add_child ("Regions");
1173 Glib::Threads::Mutex::Lock rl (region_lock);
1174 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1175 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1176 boost::shared_ptr<Region> r = i->second;
1177 /* only store regions not attached to playlists */
1178 if (r->playlist() == 0) {
1179 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1180 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1182 child->add_child_nocopy (r->get_state ());
1187 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1189 if (!cassocs.empty()) {
1190 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1192 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1194 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1195 i->first->id().print (buf, sizeof (buf));
1196 can->add_property (X_("copy"), buf);
1197 i->second->id().print (buf, sizeof (buf));
1198 can->add_property (X_("original"), buf);
1199 ca->add_child_nocopy (*can);
1209 node->add_child_nocopy (_locations->get_state());
1212 Locations loc (*this);
1213 // for a template, just create a new Locations, populate it
1214 // with the default start and end, and get the state for that.
1215 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1216 range->set (max_framepos, 0);
1218 XMLNode& locations_state = loc.get_state();
1220 if (ARDOUR::Profile->get_trx() && _locations) {
1221 // For tracks we need stored the Auto Loop Range and all MIDI markers.
1222 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1223 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1224 locations_state.add_child_nocopy ((*i)->get_state ());
1228 node->add_child_nocopy (locations_state);
1231 child = node->add_child ("Bundles");
1233 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1234 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1235 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1237 child->add_child_nocopy (b->get_state());
1242 node->add_child_nocopy (_vca_manager->get_state());
1244 child = node->add_child ("Routes");
1246 boost::shared_ptr<RouteList> r = routes.reader ();
1248 RoutePublicOrderSorter cmp;
1249 RouteList public_order (*r);
1250 public_order.sort (cmp);
1252 /* the sort should have put the monitor out first */
1255 assert (_monitor_out == public_order.front());
1258 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1259 if (!(*i)->is_auditioner()) {
1261 child->add_child_nocopy ((*i)->get_state());
1263 child->add_child_nocopy ((*i)->get_template());
1269 playlists->add_state (node, full_state);
1271 child = node->add_child ("RouteGroups");
1272 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1273 child->add_child_nocopy ((*i)->get_state());
1277 XMLNode* gain_child = node->add_child ("Click");
1278 gain_child->add_child_nocopy (_click_io->state (full_state));
1279 gain_child->add_child_nocopy (_click_gain->state (full_state));
1283 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1284 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1288 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1289 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1292 node->add_child_nocopy (_speakers->get_state());
1293 node->add_child_nocopy (_tempo_map->get_state());
1294 node->add_child_nocopy (get_control_protocol_state());
1297 node->add_child_copy (*_extra_xml);
1301 Glib::Threads::Mutex::Lock lm (lua_lock);
1304 luabridge::LuaRef savedstate ((*_lua_save)());
1305 saved = savedstate.cast<std::string>();
1307 lua.collect_garbage ();
1310 gchar* b64 = g_base64_encode ((const guchar*)saved.c_str (), saved.size ());
1311 std::string b64s (b64);
1314 XMLNode* script_node = new XMLNode (X_("Script"));
1315 script_node->add_property (X_("lua"), LUA_VERSION);
1316 script_node->add_content (b64s);
1317 node->add_child_nocopy (*script_node);
1324 Session::get_control_protocol_state ()
1326 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1327 return cpm.get_state();
1331 Session::set_state (const XMLNode& node, int version)
1336 XMLProperty const * prop;
1339 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1341 if (node.name() != X_("Session")) {
1342 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1346 if ((prop = node.property ("name")) != 0) {
1347 _name = prop->value ();
1350 if ((prop = node.property (X_("sample-rate"))) != 0) {
1352 _base_frame_rate = atoi (prop->value());
1353 _nominal_frame_rate = _base_frame_rate;
1355 assert (AudioEngine::instance()->running ());
1356 if (_base_frame_rate != AudioEngine::instance()->sample_rate ()) {
1357 boost::optional<int> r = AskAboutSampleRateMismatch (_base_frame_rate, _current_frame_rate);
1358 if (r.get_value_or (0)) {
1364 created_with = "unknown";
1365 if ((child = find_named_node (node, "ProgramVersion")) != 0) {
1366 if ((prop = child->property (X_("created-with"))) != 0) {
1367 created_with = prop->value ();
1371 setup_raid_path(_session_dir->root_path());
1373 if ((prop = node.property (X_("end-is-free"))) != 0) {
1374 _session_range_end_is_free = string_is_affirmative (prop->value());
1377 if ((prop = node.property (X_("id-counter"))) != 0) {
1379 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1380 ID::init_counter (x);
1382 /* old sessions used a timebased counter, so fake
1383 the startup ID counter based on a standard
1388 ID::init_counter (now);
1391 if ((prop = node.property (X_("name-counter"))) != 0) {
1392 init_name_id_counter (atoi (prop->value()));
1395 if ((prop = node.property (X_("event-counter"))) != 0) {
1396 Evoral::init_event_id_counter (atoi (prop->value()));
1399 if ((prop = node.property (X_("vca-counter"))) != 0) {
1401 sscanf (prop->value().c_str(), "%" PRIu32, &x);
1402 VCA::set_next_vca_number (x);
1404 VCA::set_next_vca_number (1);
1407 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1408 _midi_ports->set_midi_port_states (child->children());
1411 IO::disable_connecting ();
1413 Stateful::save_extra_xml (node);
1415 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1416 load_options (*child);
1417 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1418 load_options (*child);
1420 error << _("Session: XML state has no options section") << endmsg;
1423 if (version >= 3000) {
1424 if ((child = find_named_node (node, "Metadata")) == 0) {
1425 warning << _("Session: XML state has no metadata section") << endmsg;
1426 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1431 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1432 _speakers->set_state (*child, version);
1435 if ((child = find_named_node (node, "Sources")) == 0) {
1436 error << _("Session: XML state has no sources section") << endmsg;
1438 } else if (load_sources (*child)) {
1442 if ((child = find_named_node (node, "TempoMap")) == 0) {
1443 error << _("Session: XML state has no Tempo Map section") << endmsg;
1445 } else if (_tempo_map->set_state (*child, version)) {
1449 if ((child = find_named_node (node, "Locations")) == 0) {
1450 error << _("Session: XML state has no locations section") << endmsg;
1452 } else if (_locations->set_state (*child, version)) {
1456 locations_changed ();
1458 if (_session_range_location) {
1459 AudioFileSource::set_header_position_offset (_session_range_location->start());
1462 if ((child = find_named_node (node, "Regions")) == 0) {
1463 error << _("Session: XML state has no Regions section") << endmsg;
1465 } else if (load_regions (*child)) {
1469 if ((child = find_named_node (node, "Playlists")) == 0) {
1470 error << _("Session: XML state has no playlists section") << endmsg;
1472 } else if (playlists->load (*this, *child)) {
1476 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1478 } else if (playlists->load_unused (*this, *child)) {
1482 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1483 if (load_compounds (*child)) {
1488 if (version >= 3000) {
1489 if ((child = find_named_node (node, "Bundles")) == 0) {
1490 warning << _("Session: XML state has no bundles section") << endmsg;
1493 /* We can't load Bundles yet as they need to be able
1494 to convert from port names to Port objects, which can't happen until
1496 _bundle_xml_node = new XMLNode (*child);
1500 if (version < 3000) {
1501 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1502 error << _("Session: XML state has no diskstreams section") << endmsg;
1504 } else if (load_diskstreams_2X (*child, version)) {
1509 if ((child = find_named_node (node, VCAManager::xml_node_name)) != 0) {
1510 _vca_manager->set_state (*child, version);
1513 if ((child = find_named_node (node, "Routes")) == 0) {
1514 error << _("Session: XML state has no routes section") << endmsg;
1516 } else if (load_routes (*child, version)) {
1520 /* Now that we have Routes and masters loaded, connect them if appropriate */
1522 Slavable::Assign (_vca_manager); /* EMIT SIGNAL */
1524 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1525 _diskstreams_2X.clear ();
1527 if (version >= 3000) {
1529 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1530 error << _("Session: XML state has no route groups section") << endmsg;
1532 } else if (load_route_groups (*child, version)) {
1536 } else if (version < 3000) {
1538 if ((child = find_named_node (node, "EditGroups")) == 0) {
1539 error << _("Session: XML state has no edit groups section") << endmsg;
1541 } else if (load_route_groups (*child, version)) {
1545 if ((child = find_named_node (node, "MixGroups")) == 0) {
1546 error << _("Session: XML state has no mix groups section") << endmsg;
1548 } else if (load_route_groups (*child, version)) {
1553 if ((child = find_named_node (node, "Click")) == 0) {
1554 warning << _("Session: XML state has no click section") << endmsg;
1555 } else if (_click_io) {
1556 setup_click_state (&node);
1559 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1560 ControlProtocolManager::instance().set_state (*child, version);
1563 if ((child = find_named_node (node, "Script"))) {
1564 for (XMLNodeList::const_iterator n = child->children ().begin (); n != child->children ().end (); ++n) {
1565 if (!(*n)->is_content ()) { continue; }
1567 guchar* buf = g_base64_decode ((*n)->content ().c_str (), &size);
1569 Glib::Threads::Mutex::Lock lm (lua_lock);
1570 (*_lua_load)(std::string ((const char*)buf, size));
1571 } catch (luabridge::LuaException const& e) {
1572 cerr << "LuaException:" << e.what () << endl;
1578 update_route_record_state ();
1580 /* here beginneth the second phase ... */
1581 set_snapshot_name (_current_snapshot_name);
1583 StateReady (); /* EMIT SIGNAL */
1596 Session::load_routes (const XMLNode& node, int version)
1599 XMLNodeConstIterator niter;
1600 RouteList new_routes;
1602 nlist = node.children();
1606 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1608 boost::shared_ptr<Route> route;
1609 if (version < 3000) {
1610 route = XMLRouteFactory_2X (**niter, version);
1612 route = XMLRouteFactory (**niter, version);
1616 error << _("Session: cannot create Route from XML description.") << endmsg;
1620 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1622 new_routes.push_back (route);
1625 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1627 add_routes (new_routes, false, false, false, PresentationInfo::max_order);
1629 BootMessage (_("Finished adding tracks/busses"));
1634 boost::shared_ptr<Route>
1635 Session::XMLRouteFactory (const XMLNode& node, int version)
1637 boost::shared_ptr<Route> ret;
1639 if (node.name() != "Route") {
1643 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1645 DataType type = DataType::AUDIO;
1646 XMLProperty const * prop = node.property("default-type");
1649 type = DataType (prop->value());
1652 assert (type != DataType::NIL);
1656 boost::shared_ptr<Track> track;
1658 if (type == DataType::AUDIO) {
1659 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1661 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1664 if (track->init()) {
1668 if (track->set_state (node, version)) {
1672 BOOST_MARK_TRACK (track);
1676 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1677 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1679 if (r->init () == 0 && r->set_state (node, version) == 0) {
1680 BOOST_MARK_ROUTE (r);
1688 boost::shared_ptr<Route>
1689 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1691 boost::shared_ptr<Route> ret;
1693 if (node.name() != "Route") {
1697 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1699 ds_prop = node.property (X_("diskstream"));
1702 DataType type = DataType::AUDIO;
1703 XMLProperty const * prop = node.property("default-type");
1706 type = DataType (prop->value());
1709 assert (type != DataType::NIL);
1713 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1714 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1718 if (i == _diskstreams_2X.end()) {
1719 error << _("Could not find diskstream for route") << endmsg;
1720 return boost::shared_ptr<Route> ();
1723 boost::shared_ptr<Track> track;
1725 if (type == DataType::AUDIO) {
1726 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1728 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1731 if (track->init()) {
1735 if (track->set_state (node, version)) {
1739 track->set_diskstream (*i);
1741 BOOST_MARK_TRACK (track);
1745 PresentationInfo::Flag flags = PresentationInfo::get_flags (node);
1746 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1748 if (r->init () == 0 && r->set_state (node, version) == 0) {
1749 BOOST_MARK_ROUTE (r);
1758 Session::load_regions (const XMLNode& node)
1761 XMLNodeConstIterator niter;
1762 boost::shared_ptr<Region> region;
1764 nlist = node.children();
1768 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1769 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1770 error << _("Session: cannot create Region from XML description.");
1771 XMLProperty const * name = (**niter).property("name");
1774 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1785 Session::load_compounds (const XMLNode& node)
1787 XMLNodeList calist = node.children();
1788 XMLNodeConstIterator caiter;
1789 XMLProperty const * caprop;
1791 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1792 XMLNode* ca = *caiter;
1796 if ((caprop = ca->property (X_("original"))) == 0) {
1799 orig_id = caprop->value();
1801 if ((caprop = ca->property (X_("copy"))) == 0) {
1804 copy_id = caprop->value();
1806 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1807 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1809 if (!orig || !copy) {
1810 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1816 RegionFactory::add_compound_association (orig, copy);
1823 Session::load_nested_sources (const XMLNode& node)
1826 XMLNodeConstIterator niter;
1828 nlist = node.children();
1830 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1831 if ((*niter)->name() == "Source") {
1833 /* it may already exist, so don't recreate it unnecessarily
1836 XMLProperty const * prop = (*niter)->property (X_("id"));
1838 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1842 ID source_id (prop->value());
1844 if (!source_by_id (source_id)) {
1847 SourceFactory::create (*this, **niter, true);
1849 catch (failed_constructor& err) {
1850 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1857 boost::shared_ptr<Region>
1858 Session::XMLRegionFactory (const XMLNode& node, bool full)
1860 XMLProperty const * type = node.property("type");
1864 const XMLNodeList& nlist = node.children();
1866 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1867 XMLNode *child = (*niter);
1868 if (child->name() == "NestedSource") {
1869 load_nested_sources (*child);
1873 if (!type || type->value() == "audio") {
1874 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1875 } else if (type->value() == "midi") {
1876 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1879 } catch (failed_constructor& err) {
1880 return boost::shared_ptr<Region> ();
1883 return boost::shared_ptr<Region> ();
1886 boost::shared_ptr<AudioRegion>
1887 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1889 XMLProperty const * prop;
1890 boost::shared_ptr<Source> source;
1891 boost::shared_ptr<AudioSource> as;
1893 SourceList master_sources;
1894 uint32_t nchans = 1;
1897 if (node.name() != X_("Region")) {
1898 return boost::shared_ptr<AudioRegion>();
1901 if ((prop = node.property (X_("channels"))) != 0) {
1902 nchans = atoi (prop->value().c_str());
1905 if ((prop = node.property ("name")) == 0) {
1906 cerr << "no name for this region\n";
1910 if ((prop = node.property (X_("source-0"))) == 0) {
1911 if ((prop = node.property ("source")) == 0) {
1912 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1913 return boost::shared_ptr<AudioRegion>();
1917 PBD::ID s_id (prop->value());
1919 if ((source = source_by_id (s_id)) == 0) {
1920 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1921 return boost::shared_ptr<AudioRegion>();
1924 as = boost::dynamic_pointer_cast<AudioSource>(source);
1926 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1927 return boost::shared_ptr<AudioRegion>();
1930 sources.push_back (as);
1932 /* pickup other channels */
1934 for (uint32_t n=1; n < nchans; ++n) {
1935 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1936 if ((prop = node.property (buf)) != 0) {
1938 PBD::ID id2 (prop->value());
1940 if ((source = source_by_id (id2)) == 0) {
1941 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1942 return boost::shared_ptr<AudioRegion>();
1945 as = boost::dynamic_pointer_cast<AudioSource>(source);
1947 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1948 return boost::shared_ptr<AudioRegion>();
1950 sources.push_back (as);
1954 for (uint32_t n = 0; n < nchans; ++n) {
1955 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1956 if ((prop = node.property (buf)) != 0) {
1958 PBD::ID id2 (prop->value());
1960 if ((source = source_by_id (id2)) == 0) {
1961 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1962 return boost::shared_ptr<AudioRegion>();
1965 as = boost::dynamic_pointer_cast<AudioSource>(source);
1967 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1968 return boost::shared_ptr<AudioRegion>();
1970 master_sources.push_back (as);
1975 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1977 /* a final detail: this is the one and only place that we know how long missing files are */
1979 if (region->whole_file()) {
1980 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1981 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1983 sfp->set_length (region->length());
1988 if (!master_sources.empty()) {
1989 if (master_sources.size() != nchans) {
1990 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1992 region->set_master_sources (master_sources);
2000 catch (failed_constructor& err) {
2001 return boost::shared_ptr<AudioRegion>();
2005 boost::shared_ptr<MidiRegion>
2006 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
2008 XMLProperty const * prop;
2009 boost::shared_ptr<Source> source;
2010 boost::shared_ptr<MidiSource> ms;
2013 if (node.name() != X_("Region")) {
2014 return boost::shared_ptr<MidiRegion>();
2017 if ((prop = node.property ("name")) == 0) {
2018 cerr << "no name for this region\n";
2022 if ((prop = node.property (X_("source-0"))) == 0) {
2023 if ((prop = node.property ("source")) == 0) {
2024 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
2025 return boost::shared_ptr<MidiRegion>();
2029 PBD::ID s_id (prop->value());
2031 if ((source = source_by_id (s_id)) == 0) {
2032 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
2033 return boost::shared_ptr<MidiRegion>();
2036 ms = boost::dynamic_pointer_cast<MidiSource>(source);
2038 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
2039 return boost::shared_ptr<MidiRegion>();
2042 sources.push_back (ms);
2045 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
2046 /* a final detail: this is the one and only place that we know how long missing files are */
2048 if (region->whole_file()) {
2049 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
2050 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
2052 sfp->set_length (region->length());
2060 catch (failed_constructor& err) {
2061 return boost::shared_ptr<MidiRegion>();
2066 Session::get_sources_as_xml ()
2069 XMLNode* node = new XMLNode (X_("Sources"));
2070 Glib::Threads::Mutex::Lock lm (source_lock);
2072 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
2073 node->add_child_nocopy (i->second->get_state());
2080 Session::reset_write_sources (bool mark_write_complete, bool force)
2082 boost::shared_ptr<RouteList> rl = routes.reader();
2083 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
2084 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
2086 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
2087 tr->reset_write_sources(mark_write_complete, force);
2088 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
2094 Session::load_sources (const XMLNode& node)
2097 XMLNodeConstIterator niter;
2098 boost::shared_ptr<Source> source; /* don't need this but it stops some
2099 * versions of gcc complaining about
2100 * discarded return values.
2103 nlist = node.children();
2107 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2110 if ((source = XMLSourceFactory (**niter)) == 0) {
2111 error << _("Session: cannot create Source from XML description.") << endmsg;
2114 } catch (MissingSource& err) {
2118 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
2119 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
2120 PROGRAM_NAME) << endmsg;
2124 if (!no_questions_about_missing_files) {
2125 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
2130 switch (user_choice) {
2132 /* user added a new search location, so try again */
2137 /* user asked to quit the entire session load
2142 no_questions_about_missing_files = true;
2146 no_questions_about_missing_files = true;
2153 case DataType::AUDIO:
2154 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
2157 case DataType::MIDI:
2158 /* The MIDI file is actually missing so
2159 * just create a new one in the same
2160 * location. Do not announce its
2164 if (!Glib::path_is_absolute (err.path)) {
2165 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
2167 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2172 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2173 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2174 /* reset ID to match the missing one */
2175 source->set_id (**niter);
2176 /* Now we can announce it */
2177 SourceFactory::SourceCreated (source);
2188 boost::shared_ptr<Source>
2189 Session::XMLSourceFactory (const XMLNode& node)
2191 if (node.name() != "Source") {
2192 return boost::shared_ptr<Source>();
2196 /* note: do peak building in another thread when loading session state */
2197 return SourceFactory::create (*this, node, true);
2200 catch (failed_constructor& err) {
2201 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2202 return boost::shared_ptr<Source>();
2207 Session::save_template (string template_name, bool replace_existing)
2209 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2213 bool absolute_path = Glib::path_is_absolute (template_name);
2215 /* directory to put the template in */
2216 std::string template_dir_path;
2218 if (!absolute_path) {
2219 std::string user_template_dir(user_template_directory());
2221 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2222 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2223 user_template_dir, g_strerror (errno)) << endmsg;
2227 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2229 template_dir_path = template_name;
2232 if (!ARDOUR::Profile->get_trx()) {
2233 if (!replace_existing && Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2234 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2235 template_dir_path) << endmsg;
2239 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2240 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2241 template_dir_path, g_strerror (errno)) << endmsg;
2247 std::string template_file_path;
2249 if (ARDOUR::Profile->get_trx()) {
2250 template_file_path = template_name;
2252 if (absolute_path) {
2253 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2255 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2259 SessionSaveUnderway (); /* EMIT SIGNAL */
2264 PBD::Unwinder<std::string> uw (_template_state_dir, template_dir_path);
2265 tree.set_root (&get_template());
2268 if (!tree.write (template_file_path)) {
2269 error << _("template not saved") << endmsg;
2273 store_recent_templates (template_file_path);
2279 Session::refresh_disk_space ()
2281 #if __APPLE__ || __FreeBSD__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2283 Glib::Threads::Mutex::Lock lm (space_lock);
2285 /* get freespace on every FS that is part of the session path */
2287 _total_free_4k_blocks = 0;
2288 _total_free_4k_blocks_uncertain = false;
2290 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2292 struct statfs statfsbuf;
2293 statfs (i->path.c_str(), &statfsbuf);
2295 double const scale = statfsbuf.f_bsize / 4096.0;
2297 /* See if this filesystem is read-only */
2298 struct statvfs statvfsbuf;
2299 statvfs (i->path.c_str(), &statvfsbuf);
2301 /* f_bavail can be 0 if it is undefined for whatever
2302 filesystem we are looking at; Samba shares mounted
2303 via GVFS are an example of this.
2305 if (statfsbuf.f_bavail == 0) {
2306 /* block count unknown */
2308 i->blocks_unknown = true;
2309 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2310 /* read-only filesystem */
2312 i->blocks_unknown = false;
2314 /* read/write filesystem with known space */
2315 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2316 i->blocks_unknown = false;
2319 _total_free_4k_blocks += i->blocks;
2320 if (i->blocks_unknown) {
2321 _total_free_4k_blocks_uncertain = true;
2324 #elif defined PLATFORM_WINDOWS
2325 vector<string> scanned_volumes;
2326 vector<string>::iterator j;
2327 vector<space_and_path>::iterator i;
2328 DWORD nSectorsPerCluster, nBytesPerSector,
2329 nFreeClusters, nTotalClusters;
2333 _total_free_4k_blocks = 0;
2335 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2336 strncpy (disk_drive, (*i).path.c_str(), 3);
2340 volume_found = false;
2341 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2343 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2344 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2345 i->blocks = (uint32_t)(nFreeBytes / 4096);
2347 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2348 if (0 == j->compare(disk_drive)) {
2349 volume_found = true;
2354 if (!volume_found) {
2355 scanned_volumes.push_back(disk_drive);
2356 _total_free_4k_blocks += i->blocks;
2361 if (0 == _total_free_4k_blocks) {
2362 strncpy (disk_drive, path().c_str(), 3);
2365 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2367 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2368 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2369 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2376 Session::get_best_session_directory_for_new_audio ()
2378 vector<space_and_path>::iterator i;
2379 string result = _session_dir->root_path();
2381 /* handle common case without system calls */
2383 if (session_dirs.size() == 1) {
2387 /* OK, here's the algorithm we're following here:
2389 We want to select which directory to use for
2390 the next file source to be created. Ideally,
2391 we'd like to use a round-robin process so as to
2392 get maximum performance benefits from splitting
2393 the files across multiple disks.
2395 However, in situations without much diskspace, an
2396 RR approach may end up filling up a filesystem
2397 with new files while others still have space.
2398 Its therefore important to pay some attention to
2399 the freespace in the filesystem holding each
2400 directory as well. However, if we did that by
2401 itself, we'd keep creating new files in the file
2402 system with the most space until it was as full
2403 as all others, thus negating any performance
2404 benefits of this RAID-1 like approach.
2406 So, we use a user-configurable space threshold. If
2407 there are at least 2 filesystems with more than this
2408 much space available, we use RR selection between them.
2409 If not, then we pick the filesystem with the most space.
2411 This gets a good balance between the two
2415 refresh_disk_space ();
2417 int free_enough = 0;
2419 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2420 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2425 if (free_enough >= 2) {
2426 /* use RR selection process, ensuring that the one
2430 i = last_rr_session_dir;
2433 if (++i == session_dirs.end()) {
2434 i = session_dirs.begin();
2437 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2438 SessionDirectory sdir(i->path);
2439 if (sdir.create ()) {
2441 last_rr_session_dir = i;
2446 } while (i != last_rr_session_dir);
2450 /* pick FS with the most freespace (and that
2451 seems to actually work ...)
2454 vector<space_and_path> sorted;
2455 space_and_path_ascending_cmp cmp;
2457 sorted = session_dirs;
2458 sort (sorted.begin(), sorted.end(), cmp);
2460 for (i = sorted.begin(); i != sorted.end(); ++i) {
2461 SessionDirectory sdir(i->path);
2462 if (sdir.create ()) {
2464 last_rr_session_dir = i;
2474 Session::automation_dir () const
2476 return Glib::build_filename (_path, automation_dir_name);
2480 Session::analysis_dir () const
2482 return Glib::build_filename (_path, analysis_dir_name);
2486 Session::plugins_dir () const
2488 return Glib::build_filename (_path, plugins_dir_name);
2492 Session::externals_dir () const
2494 return Glib::build_filename (_path, externals_dir_name);
2498 Session::load_bundles (XMLNode const & node)
2500 XMLNodeList nlist = node.children();
2501 XMLNodeConstIterator niter;
2505 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2506 if ((*niter)->name() == "InputBundle") {
2507 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2508 } else if ((*niter)->name() == "OutputBundle") {
2509 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2511 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2520 Session::load_route_groups (const XMLNode& node, int version)
2522 XMLNodeList nlist = node.children();
2523 XMLNodeConstIterator niter;
2527 if (version >= 3000) {
2529 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2530 if ((*niter)->name() == "RouteGroup") {
2531 RouteGroup* rg = new RouteGroup (*this, "");
2532 add_route_group (rg);
2533 rg->set_state (**niter, version);
2537 } else if (version < 3000) {
2539 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2540 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2541 RouteGroup* rg = new RouteGroup (*this, "");
2542 add_route_group (rg);
2543 rg->set_state (**niter, version);
2552 state_file_filter (const string &str, void* /*arg*/)
2554 return (str.length() > strlen(statefile_suffix) &&
2555 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2559 remove_end(string state)
2561 string statename(state);
2563 string::size_type start,end;
2564 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2565 statename = statename.substr (start+1);
2568 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2569 end = statename.length();
2572 return string(statename.substr (0, end));
2576 Session::possible_states (string path)
2578 vector<string> states;
2579 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2581 transform(states.begin(), states.end(), states.begin(), remove_end);
2583 sort (states.begin(), states.end());
2589 Session::possible_states () const
2591 return possible_states(_path);
2595 Session::add_route_group (RouteGroup* g)
2597 _route_groups.push_back (g);
2598 route_group_added (g); /* EMIT SIGNAL */
2600 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2601 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2602 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2608 Session::remove_route_group (RouteGroup& rg)
2610 list<RouteGroup*>::iterator i;
2612 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2613 _route_groups.erase (i);
2616 route_group_removed (); /* EMIT SIGNAL */
2620 /** Set a new order for our route groups, without adding or removing any.
2621 * @param groups Route group list in the new order.
2624 Session::reorder_route_groups (list<RouteGroup*> groups)
2626 _route_groups = groups;
2628 route_groups_reordered (); /* EMIT SIGNAL */
2634 Session::route_group_by_name (string name)
2636 list<RouteGroup *>::iterator i;
2638 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2639 if ((*i)->name() == name) {
2647 Session::all_route_group() const
2649 return *_all_route_group;
2653 Session::add_commands (vector<Command*> const & cmds)
2655 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2661 Session::add_command (Command* const cmd)
2663 assert (_current_trans);
2664 DEBUG_UNDO_HISTORY (
2665 string_compose ("Current Undo Transaction %1, adding command: %2",
2666 _current_trans->name (),
2668 _current_trans->add_command (cmd);
2671 PBD::StatefulDiffCommand*
2672 Session::add_stateful_diff_command (boost::shared_ptr<PBD::StatefulDestructible> sfd)
2674 PBD::StatefulDiffCommand* cmd = new PBD::StatefulDiffCommand (sfd);
2680 Session::begin_reversible_command (const string& name)
2682 begin_reversible_command (g_quark_from_string (name.c_str ()));
2685 /** Begin a reversible command using a GQuark to identify it.
2686 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2687 * but there must be as many begin...()s as there are commit...()s.
2690 Session::begin_reversible_command (GQuark q)
2692 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2693 to hold all the commands that are committed. This keeps the order of
2694 commands correct in the history.
2697 if (_current_trans == 0) {
2698 DEBUG_UNDO_HISTORY (string_compose (
2699 "Begin Reversible Command, new transaction: %1", g_quark_to_string (q)));
2701 /* start a new transaction */
2702 assert (_current_trans_quarks.empty ());
2703 _current_trans = new UndoTransaction();
2704 _current_trans->set_name (g_quark_to_string (q));
2706 DEBUG_UNDO_HISTORY (
2707 string_compose ("Begin Reversible Command, current transaction: %1",
2708 _current_trans->name ()));
2711 _current_trans_quarks.push_front (q);
2715 Session::abort_reversible_command ()
2717 if (_current_trans != 0) {
2718 DEBUG_UNDO_HISTORY (
2719 string_compose ("Abort Reversible Command: %1", _current_trans->name ()));
2720 _current_trans->clear();
2721 delete _current_trans;
2723 _current_trans_quarks.clear();
2728 Session::commit_reversible_command (Command *cmd)
2730 assert (_current_trans);
2731 assert (!_current_trans_quarks.empty ());
2736 DEBUG_UNDO_HISTORY (
2737 string_compose ("Current Undo Transaction %1, adding command: %2",
2738 _current_trans->name (),
2740 _current_trans->add_command (cmd);
2743 DEBUG_UNDO_HISTORY (
2744 string_compose ("Commit Reversible Command, current transaction: %1",
2745 _current_trans->name ()));
2747 _current_trans_quarks.pop_front ();
2749 if (!_current_trans_quarks.empty ()) {
2750 DEBUG_UNDO_HISTORY (
2751 string_compose ("Commit Reversible Command, transaction is not "
2752 "top-level, current transaction: %1",
2753 _current_trans->name ()));
2754 /* the transaction we're committing is not the top-level one */
2758 if (_current_trans->empty()) {
2759 /* no commands were added to the transaction, so just get rid of it */
2760 DEBUG_UNDO_HISTORY (
2761 string_compose ("Commit Reversible Command, No commands were "
2762 "added to current transaction: %1",
2763 _current_trans->name ()));
2764 delete _current_trans;
2769 gettimeofday (&now, 0);
2770 _current_trans->set_timestamp (now);
2772 _history.add (_current_trans);
2777 accept_all_audio_files (const string& path, void* /*arg*/)
2779 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2783 if (!AudioFileSource::safe_audio_file_extension (path)) {
2791 accept_all_midi_files (const string& path, void* /*arg*/)
2793 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2797 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2798 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2799 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2803 accept_all_state_files (const string& path, void* /*arg*/)
2805 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2809 std::string const statefile_ext (statefile_suffix);
2810 if (path.length() >= statefile_ext.length()) {
2811 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2818 Session::find_all_sources (string path, set<string>& result)
2823 if (!tree.read (path)) {
2827 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2832 XMLNodeConstIterator niter;
2834 nlist = node->children();
2838 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2840 XMLProperty const * prop;
2842 if ((prop = (*niter)->property (X_("type"))) == 0) {
2846 DataType type (prop->value());
2848 if ((prop = (*niter)->property (X_("name"))) == 0) {
2852 if (Glib::path_is_absolute (prop->value())) {
2853 /* external file, ignore */
2861 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2862 result.insert (found_path);
2870 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2872 vector<string> state_files;
2874 string this_snapshot_path;
2880 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2881 ripped = ripped.substr (0, ripped.length() - 1);
2884 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2886 if (state_files.empty()) {
2891 this_snapshot_path = Glib::build_filename (_path, legalize_for_path (_current_snapshot_name));
2892 this_snapshot_path += statefile_suffix;
2894 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2896 cerr << "Looking at snapshot " << (*i) << " ( with this = [" << this_snapshot_path << "])\n";
2898 if (exclude_this_snapshot && *i == this_snapshot_path) {
2899 cerr << "\texcluded\n";
2904 if (find_all_sources (*i, result) < 0) {
2912 struct RegionCounter {
2913 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2914 AudioSourceList::iterator iter;
2915 boost::shared_ptr<Region> region;
2918 RegionCounter() : count (0) {}
2922 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2924 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2925 return r.get_value_or (1);
2929 Session::cleanup_regions ()
2931 bool removed = false;
2932 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2934 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2936 uint32_t used = playlists->region_use_count (i->second);
2938 if (used == 0 && !i->second->automatic ()) {
2939 boost::weak_ptr<Region> w = i->second;
2942 RegionFactory::map_remove (w);
2949 // re-check to remove parent references of compound regions
2950 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end();) {
2951 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2955 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2956 if (0 == playlists->region_use_count (i->second)) {
2957 boost::weak_ptr<Region> w = i->second;
2959 RegionFactory::map_remove (w);
2966 /* dump the history list */
2973 Session::can_cleanup_peakfiles () const
2975 if (deletion_in_progress()) {
2978 if (!_writable || (_state_of_the_state & CannotSave)) {
2979 warning << _("Cannot cleanup peak-files for read-only session.") << endmsg;
2982 if (record_status() == Recording) {
2983 error << _("Cannot cleanup peak-files while recording") << endmsg;
2990 Session::cleanup_peakfiles ()
2992 Glib::Threads::Mutex::Lock lm (peak_cleanup_lock, Glib::Threads::TRY_LOCK);
2997 assert (can_cleanup_peakfiles ());
2998 assert (!peaks_cleanup_in_progres());
3000 _state_of_the_state = StateOfTheState (_state_of_the_state | PeakCleanup);
3002 int timeout = 5000; // 5 seconds
3003 while (!SourceFactory::files_with_peaks.empty()) {
3004 Glib::usleep (1000);
3005 if (--timeout < 0) {
3006 warning << _("Timeout waiting for peak-file creation to terminate before cleanup, please try again later.") << endmsg;
3007 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3012 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3013 boost::shared_ptr<AudioSource> as;
3014 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3015 as->close_peakfile();
3019 PBD::clear_directory (session_directory().peak_path());
3021 _state_of_the_state = StateOfTheState (_state_of_the_state & (~PeakCleanup));
3023 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3024 boost::shared_ptr<AudioSource> as;
3025 if ((as = boost::dynamic_pointer_cast<AudioSource> (i->second)) != 0) {
3026 SourceFactory::setup_peakfile(as, true);
3033 merge_all_sources (boost::shared_ptr<const Playlist> pl, std::set<boost::shared_ptr<Source> >* all_sources)
3035 pl->deep_sources (*all_sources);
3039 Session::cleanup_sources (CleanupReport& rep)
3041 // FIXME: needs adaptation to midi
3043 vector<boost::shared_ptr<Source> > dead_sources;
3046 vector<string> candidates;
3047 vector<string> unused;
3048 set<string> sources_used_by_all_snapshots;
3055 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
3057 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
3059 /* this is mostly for windows which doesn't allow file
3060 * renaming if the file is in use. But we don't special
3061 * case it because we need to know if this causes
3062 * problems, and the easiest way to notice that is to
3063 * keep it in place for all platforms.
3066 request_stop (false);
3068 _butler->wait_until_finished ();
3070 /* consider deleting all unused playlists */
3072 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
3077 /* sync the "all regions" property of each playlist with its current state
3080 playlists->sync_all_regions_with_regions ();
3082 /* find all un-used sources */
3087 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3089 SourceMap::iterator tmp;
3094 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
3098 if (!i->second->used() && (i->second->length(i->second->timeline_position()) > 0)) {
3099 dead_sources.push_back (i->second);
3100 i->second->drop_references ();
3106 /* build a list of all the possible audio directories for the session */
3108 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3109 SessionDirectory sdir ((*i).path);
3110 asp += sdir.sound_path();
3112 audio_path += asp.to_string();
3115 /* build a list of all the possible midi directories for the session */
3117 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3118 SessionDirectory sdir ((*i).path);
3119 msp += sdir.midi_path();
3121 midi_path += msp.to_string();
3123 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
3124 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
3126 /* add sources from all other snapshots as "used", but don't use this
3127 snapshot because the state file on disk still references sources we
3128 may have already dropped.
3131 find_all_sources_across_snapshots (sources_used_by_all_snapshots, true);
3133 /* Although the region factory has a list of all regions ever created
3134 * for this session, we're only interested in regions actually in
3135 * playlists right now. So merge all playlist regions lists together.
3137 * This will include the playlists used within compound regions.
3140 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot));
3142 /* add our current source list
3145 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
3146 boost::shared_ptr<FileSource> fs;
3147 SourceMap::iterator tmp = i;
3150 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) == 0) {
3156 /* this is mostly for windows which doesn't allow file
3157 * renaming if the file is in use. But we do not special
3158 * case it because we need to know if this causes
3159 * problems, and the easiest way to notice that is to
3160 * keep it in place for all platforms.
3165 if (!fs->is_stub()) {
3167 /* Note that we're checking a list of all
3168 * sources across all snapshots with the list
3169 * of sources used by this snapshot.
3172 if (sources_used_by_this_snapshot.find (i->second) != sources_used_by_this_snapshot.end()) {
3173 /* this source is in use by this snapshot */
3174 sources_used_by_all_snapshots.insert (fs->path());
3175 cerr << "Source from source list found in used_by_this_snapshot (" << fs->path() << ")\n";
3177 cerr << "Source from source list NOT found in used_by_this_snapshot (" << fs->path() << ")\n";
3178 /* this source is NOT in use by this snapshot
3181 /* remove all related regions from RegionFactory master list
3184 RegionFactory::remove_regions_using_source (i->second);
3186 /* remove from our current source list
3187 * also. We may not remove it from
3188 * disk, because it may be used by
3189 * other snapshots, but it isn't used inside this
3190 * snapshot anymore, so we don't need a
3201 /* now check each candidate source to see if it exists in the list of
3202 sources_used_by_all_snapshots. If it doesn't, put it into "unused".
3205 cerr << "Candidates: " << candidates.size() << endl;
3206 cerr << "Used by others: " << sources_used_by_all_snapshots.size() << endl;
3208 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
3213 for (set<string>::iterator i = sources_used_by_all_snapshots.begin(); i != sources_used_by_all_snapshots.end(); ++i) {
3215 tmppath1 = canonical_path (spath);
3216 tmppath2 = canonical_path ((*i));
3218 cerr << "\t => " << tmppath2 << endl;
3220 if (tmppath1 == tmppath2) {
3227 unused.push_back (spath);
3231 cerr << "Actually unused: " << unused.size() << endl;
3233 if (unused.empty()) {
3239 /* now try to move all unused files into the "dead" directory(ies) */
3241 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
3246 /* don't move the file across filesystems, just
3247 stick it in the `dead_dir_name' directory
3248 on whichever filesystem it was already on.
3251 if ((*x).find ("/sounds/") != string::npos) {
3253 /* old school, go up 1 level */
3255 newpath = Glib::path_get_dirname (*x); // "sounds"
3256 newpath = Glib::path_get_dirname (newpath); // "session-name"
3260 /* new school, go up 4 levels */
3262 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
3263 newpath = Glib::path_get_dirname (newpath); // "session-name"
3264 newpath = Glib::path_get_dirname (newpath); // "interchange"
3265 newpath = Glib::path_get_dirname (newpath); // "session-dir"
3268 newpath = Glib::build_filename (newpath, dead_dir_name);
3270 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
3271 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
3275 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
3277 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
3279 /* the new path already exists, try versioning */
3281 char buf[PATH_MAX+1];
3285 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
3288 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
3289 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
3293 if (version == 999) {
3294 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
3298 newpath = newpath_v;
3303 if ((g_stat ((*x).c_str(), &statbuf) != 0) || (::g_rename ((*x).c_str(), newpath.c_str()) != 0)) {
3304 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"), (*x),
3305 newpath, g_strerror (errno)) << endmsg;
3309 /* see if there an easy to find peakfile for this file, and remove it.
3312 string base = Glib::path_get_basename (*x);
3313 base += "%A"; /* this is what we add for the channel suffix of all native files,
3314 or for the first channel of embedded files. it will miss
3315 some peakfiles for other channels
3317 string peakpath = construct_peak_filepath (base);
3319 if (Glib::file_test (peakpath.c_str (), Glib::FILE_TEST_EXISTS)) {
3320 if (::g_unlink (peakpath.c_str ()) != 0) {
3321 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"), peakpath, _path,
3322 g_strerror (errno)) << endmsg;
3323 /* try to back out */
3324 ::g_rename (newpath.c_str (), _path.c_str ());
3329 rep.paths.push_back (*x);
3330 rep.space += statbuf.st_size;
3333 /* dump the history list */
3337 /* save state so we don't end up a session file
3338 referring to non-existent sources.
3345 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3351 Session::cleanup_trash_sources (CleanupReport& rep)
3353 // FIXME: needs adaptation for MIDI
3355 vector<space_and_path>::iterator i;
3361 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3363 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3365 clear_directory (dead_dir, &rep.space, &rep.paths);
3372 Session::set_dirty ()
3374 /* never mark session dirty during loading */
3376 if (_state_of_the_state & Loading) {
3380 bool was_dirty = dirty();
3382 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3386 DirtyChanged(); /* EMIT SIGNAL */
3392 Session::set_clean ()
3394 bool was_dirty = dirty();
3396 _state_of_the_state = Clean;
3400 DirtyChanged(); /* EMIT SIGNAL */
3405 Session::set_deletion_in_progress ()
3407 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3411 Session::clear_deletion_in_progress ()
3413 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3417 Session::add_controllable (boost::shared_ptr<Controllable> c)
3419 /* this adds a controllable to the list managed by the Session.
3420 this is a subset of those managed by the Controllable class
3421 itself, and represents the only ones whose state will be saved
3422 as part of the session.
3425 Glib::Threads::Mutex::Lock lm (controllables_lock);
3426 controllables.insert (c);
3429 struct null_deleter { void operator()(void const *) const {} };
3432 Session::remove_controllable (Controllable* c)
3434 if (_state_of_the_state & Deletion) {
3438 Glib::Threads::Mutex::Lock lm (controllables_lock);
3440 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3442 if (x != controllables.end()) {
3443 controllables.erase (x);
3447 boost::shared_ptr<Controllable>
3448 Session::controllable_by_id (const PBD::ID& id)
3450 Glib::Threads::Mutex::Lock lm (controllables_lock);
3452 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3453 if ((*i)->id() == id) {
3458 return boost::shared_ptr<Controllable>();
3461 boost::shared_ptr<Controllable>
3462 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3464 boost::shared_ptr<Controllable> c;
3465 boost::shared_ptr<Stripable> s;
3466 boost::shared_ptr<Route> r;
3468 switch (desc.top_level_type()) {
3469 case ControllableDescriptor::NamedRoute:
3471 std::string str = desc.top_level_name();
3473 if (str == "Master" || str == "master") {
3475 } else if (str == "control" || str == "listen" || str == "monitor" || str == "Monitor") {
3477 } else if (str == "auditioner") {
3480 s = route_by_name (desc.top_level_name());
3486 case ControllableDescriptor::PresentationOrderRoute:
3487 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Route);
3490 case ControllableDescriptor::PresentationOrderTrack:
3491 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Track);
3494 case ControllableDescriptor::PresentationOrderBus:
3495 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::Bus);
3498 case ControllableDescriptor::PresentationOrderVCA:
3499 s = get_remote_nth_stripable (desc.presentation_order(), PresentationInfo::VCA);
3502 case ControllableDescriptor::SelectionCount:
3503 s = route_by_selected_count (desc.selection_id());
3511 r = boost::dynamic_pointer_cast<Route> (s);
3513 switch (desc.subtype()) {
3514 case ControllableDescriptor::Gain:
3515 c = s->gain_control ();
3518 case ControllableDescriptor::Trim:
3519 c = s->trim_control ();
3522 case ControllableDescriptor::Solo:
3523 c = s->solo_control();
3526 case ControllableDescriptor::Mute:
3527 c = s->mute_control();
3530 case ControllableDescriptor::Recenable:
3531 c = s->rec_enable_control ();
3534 case ControllableDescriptor::PanDirection:
3535 c = s->pan_azimuth_control();
3538 case ControllableDescriptor::PanWidth:
3539 c = s->pan_width_control();
3542 case ControllableDescriptor::PanElevation:
3543 c = s->pan_elevation_control();
3546 case ControllableDescriptor::Balance:
3547 /* XXX simple pan control */
3550 case ControllableDescriptor::PluginParameter:
3552 uint32_t plugin = desc.target (0);
3553 uint32_t parameter_index = desc.target (1);
3555 /* revert to zero based counting */
3561 if (parameter_index > 0) {
3569 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3572 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3573 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3578 case ControllableDescriptor::SendGain: {
3579 uint32_t send = desc.target (0);
3586 c = r->send_level_controllable (send);
3591 /* relax and return a null pointer */
3599 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3602 Stateful::add_instant_xml (node, _path);
3605 if (write_to_config) {
3606 Config->add_instant_xml (node);
3611 Session::instant_xml (const string& node_name)
3613 return Stateful::instant_xml (node_name, _path);
3617 Session::save_history (string snapshot_name)
3625 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3626 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3630 if (snapshot_name.empty()) {
3631 snapshot_name = _current_snapshot_name;
3634 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3635 const string backup_filename = history_filename + backup_suffix;
3636 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3637 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3639 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3640 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3641 error << _("could not backup old history file, current history not saved") << endmsg;
3646 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3648 if (!tree.write (xml_path))
3650 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3652 if (g_remove (xml_path.c_str()) != 0) {
3653 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3654 xml_path, g_strerror (errno)) << endmsg;
3656 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3657 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3658 backup_path, g_strerror (errno)) << endmsg;
3668 Session::restore_history (string snapshot_name)
3672 if (snapshot_name.empty()) {
3673 snapshot_name = _current_snapshot_name;
3676 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3677 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3679 info << "Loading history from " << xml_path << endmsg;
3681 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3682 info << string_compose (_("%1: no history file \"%2\" for this session."),
3683 _name, xml_path) << endmsg;
3687 if (!tree.read (xml_path)) {
3688 error << string_compose (_("Could not understand session history file \"%1\""),
3689 xml_path) << endmsg;
3696 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3699 UndoTransaction* ut = new UndoTransaction ();
3702 ut->set_name(t->property("name")->value());
3703 stringstream ss(t->property("tv-sec")->value());
3705 ss.str(t->property("tv-usec")->value());
3707 ut->set_timestamp(tv);
3709 for (XMLNodeConstIterator child_it = t->children().begin();
3710 child_it != t->children().end(); child_it++)
3712 XMLNode *n = *child_it;
3715 if (n->name() == "MementoCommand" ||
3716 n->name() == "MementoUndoCommand" ||
3717 n->name() == "MementoRedoCommand") {
3719 if ((c = memento_command_factory(n))) {
3723 } else if (n->name() == "NoteDiffCommand") {
3724 PBD::ID id (n->property("midi-source")->value());
3725 boost::shared_ptr<MidiSource> midi_source =
3726 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3728 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3730 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3733 } else if (n->name() == "SysExDiffCommand") {
3735 PBD::ID id (n->property("midi-source")->value());
3736 boost::shared_ptr<MidiSource> midi_source =
3737 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3739 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3741 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3744 } else if (n->name() == "PatchChangeDiffCommand") {
3746 PBD::ID id (n->property("midi-source")->value());
3747 boost::shared_ptr<MidiSource> midi_source =
3748 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3750 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3752 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3755 } else if (n->name() == "StatefulDiffCommand") {
3756 if ((c = stateful_diff_command_factory (n))) {
3757 ut->add_command (c);
3760 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3771 Session::config_changed (std::string p, bool ours)
3777 if (p == "seamless-loop") {
3779 } else if (p == "rf-speed") {
3781 } else if (p == "auto-loop") {
3783 } else if (p == "auto-input") {
3785 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3786 /* auto-input only makes a difference if we're rolling */
3787 set_track_monitor_input_status (!config.get_auto_input());
3790 } else if (p == "punch-in") {
3794 if ((location = _locations->auto_punch_location()) != 0) {
3796 if (config.get_punch_in ()) {
3797 replace_event (SessionEvent::PunchIn, location->start());
3799 remove_event (location->start(), SessionEvent::PunchIn);
3803 } else if (p == "punch-out") {
3807 if ((location = _locations->auto_punch_location()) != 0) {
3809 if (config.get_punch_out()) {
3810 replace_event (SessionEvent::PunchOut, location->end());
3812 clear_events (SessionEvent::PunchOut);
3816 } else if (p == "edit-mode") {
3818 Glib::Threads::Mutex::Lock lm (playlists->lock);
3820 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3821 (*i)->set_edit_mode (Config->get_edit_mode ());
3824 } else if (p == "use-video-sync") {
3826 waiting_for_sync_offset = config.get_use_video_sync();
3828 } else if (p == "mmc-control") {
3830 //poke_midi_thread ();
3832 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3834 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3836 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3838 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3840 } else if (p == "midi-control") {
3842 //poke_midi_thread ();
3844 } else if (p == "raid-path") {
3846 setup_raid_path (config.get_raid_path());
3848 } else if (p == "timecode-format") {
3852 } else if (p == "video-pullup") {
3856 } else if (p == "seamless-loop") {
3858 if (play_loop && transport_rolling()) {
3859 // to reset diskstreams etc
3860 request_play_loop (true);
3863 } else if (p == "rf-speed") {
3865 cumulative_rf_motion = 0;
3868 } else if (p == "click-sound") {
3870 setup_click_sounds (1);
3872 } else if (p == "click-emphasis-sound") {
3874 setup_click_sounds (-1);
3876 } else if (p == "clicking") {
3878 if (Config->get_clicking()) {
3879 if (_click_io && click_data) { // don't require emphasis data
3886 } else if (p == "click-gain") {
3889 _click_gain->gain_control()->set_value (Config->get_click_gain(), Controllable::NoGroup);
3892 } else if (p == "send-mtc") {
3894 if (Config->get_send_mtc ()) {
3895 /* mark us ready to send */
3896 next_quarter_frame_to_send = 0;
3899 } else if (p == "send-mmc") {
3901 _mmc->enable_send (Config->get_send_mmc ());
3903 } else if (p == "midi-feedback") {
3905 session_midi_feedback = Config->get_midi_feedback();
3907 } else if (p == "jack-time-master") {
3909 engine().reset_timebase ();
3911 } else if (p == "native-file-header-format") {
3913 if (!first_file_header_format_reset) {
3914 reset_native_file_format ();
3917 first_file_header_format_reset = false;
3919 } else if (p == "native-file-data-format") {
3921 if (!first_file_data_format_reset) {
3922 reset_native_file_format ();
3925 first_file_data_format_reset = false;
3927 } else if (p == "external-sync") {
3928 if (!config.get_external_sync()) {
3929 drop_sync_source ();
3931 switch_to_sync_source (Config->get_sync_source());
3933 } else if (p == "denormal-model") {
3935 } else if (p == "history-depth") {
3936 set_history_depth (Config->get_history_depth());
3937 } else if (p == "remote-model") {
3938 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3941 } else if (p == "initial-program-change") {
3943 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3946 buf[0] = MIDI::program; // channel zero by default
3947 buf[1] = (Config->get_initial_program_change() & 0x7f);
3949 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3951 } else if (p == "solo-mute-override") {
3952 // catch_up_on_solo_mute_override ();
3953 } else if (p == "listen-position" || p == "pfl-position") {
3954 listen_position_changed ();
3955 } else if (p == "solo-control-is-listen-control") {
3956 solo_control_mode_changed ();
3957 } else if (p == "solo-mute-gain") {
3958 _solo_cut_control->Changed (true, Controllable::NoGroup);
3959 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3960 last_timecode_valid = false;
3961 } else if (p == "playback-buffer-seconds") {
3962 AudioSource::allocate_working_buffers (frame_rate());
3963 } else if (p == "ltc-source-port") {
3964 reconnect_ltc_input ();
3965 } else if (p == "ltc-sink-port") {
3966 reconnect_ltc_output ();
3967 } else if (p == "timecode-generator-offset") {
3968 ltc_tx_parse_offset();
3969 } else if (p == "auto-return-target-list") {
3970 follow_playhead_priority ();
3977 Session::set_history_depth (uint32_t d)
3979 _history.set_depth (d);
3983 Session::load_diskstreams_2X (XMLNode const & node, int)
3986 XMLNodeConstIterator citer;
3988 clist = node.children();
3990 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3993 /* diskstreams added automatically by DiskstreamCreated handler */
3994 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3995 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3996 _diskstreams_2X.push_back (dsp);
3998 error << _("Session: unknown diskstream type in XML") << endmsg;
4002 catch (failed_constructor& err) {
4003 error << _("Session: could not load diskstream via XML state") << endmsg;
4011 /** Connect things to the MMC object */
4013 Session::setup_midi_machine_control ()
4015 _mmc = new MIDI::MachineControl;
4017 boost::shared_ptr<AsyncMIDIPort> async_in = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_input_port());
4018 boost::shared_ptr<AsyncMIDIPort> async_out = boost::dynamic_pointer_cast<AsyncMIDIPort> (_midi_ports->mmc_output_port());
4020 if (!async_out || !async_out) {
4024 /* XXXX argh, passing raw pointers back into libmidi++ */
4026 MIDI::Port* mmc_in = async_in.get();
4027 MIDI::Port* mmc_out = async_out.get();
4029 _mmc->set_ports (mmc_in, mmc_out);
4031 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4032 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
4033 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
4034 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
4035 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
4036 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
4037 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
4038 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
4039 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
4040 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
4041 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
4042 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
4043 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
4045 /* also handle MIDI SPP because its so common */
4047 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
4048 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
4049 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
4052 boost::shared_ptr<Controllable>
4053 Session::solo_cut_control() const
4055 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
4056 controls in Ardour that currently get presented to the user in the GUI that require
4057 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
4059 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
4060 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
4064 return _solo_cut_control;
4068 Session::save_snapshot_name (const std::string & n)
4070 /* assure Stateful::_instant_xml is loaded
4071 * add_instant_xml() only adds to existing data and defaults
4072 * to use an empty Tree otherwise
4074 instant_xml ("LastUsedSnapshot");
4076 XMLNode* last_used_snapshot = new XMLNode ("LastUsedSnapshot");
4077 last_used_snapshot->add_property ("name", string(n));
4078 add_instant_xml (*last_used_snapshot, false);
4082 Session::set_snapshot_name (const std::string & n)
4084 _current_snapshot_name = n;
4085 save_snapshot_name (n);
4089 Session::rename (const std::string& new_name)
4091 string legal_name = legalize_for_path (new_name);
4097 string const old_sources_root = _session_dir->sources_root();
4099 if (!_writable || (_state_of_the_state & CannotSave)) {
4100 error << _("Cannot rename read-only session.") << endmsg;
4101 return 0; // don't show "messed up" warning
4103 if (record_status() == Recording) {
4104 error << _("Cannot rename session while recording") << endmsg;
4105 return 0; // don't show "messed up" warning
4108 StateProtector stp (this);
4113 * interchange subdirectory
4117 * Backup files are left unchanged and not renamed.
4120 /* Windows requires that we close all files before attempting the
4121 * rename. This works on other platforms, but isn't necessary there.
4122 * Leave it in place for all platforms though, since it may help
4123 * catch issues that could arise if the way Source files work ever
4124 * change (since most developers are not using Windows).
4127 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4128 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4134 /* pass one: not 100% safe check that the new directory names don't
4138 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4142 /* this is a stupid hack because Glib::path_get_dirname() is
4143 * lexical-only, and so passing it /a/b/c/ gives a different
4144 * result than passing it /a/b/c ...
4147 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4148 oldstr = oldstr.substr (0, oldstr.length() - 1);
4151 string base = Glib::path_get_dirname (oldstr);
4153 newstr = Glib::build_filename (base, legal_name);
4155 cerr << "Looking for " << newstr << endl;
4157 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
4158 cerr << " exists\n";
4167 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
4173 /* this is a stupid hack because Glib::path_get_dirname() is
4174 * lexical-only, and so passing it /a/b/c/ gives a different
4175 * result than passing it /a/b/c ...
4178 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
4179 oldstr = oldstr.substr (0, oldstr.length() - 1);
4182 string base = Glib::path_get_dirname (oldstr);
4183 newstr = Glib::build_filename (base, legal_name);
4185 cerr << "for " << oldstr << " new dir = " << newstr << endl;
4187 cerr << "Rename " << oldstr << " => " << newstr << endl;
4188 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4189 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4190 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4194 /* Reset path in "session dirs" */
4199 /* reset primary SessionDirectory object */
4202 (*_session_dir) = newstr;
4207 /* now rename directory below session_dir/interchange */
4209 string old_interchange_dir;
4210 string new_interchange_dir;
4212 /* use newstr here because we renamed the path
4213 * (folder/directory) that used to be oldstr to newstr above
4216 v.push_back (newstr);
4217 v.push_back (interchange_dir_name);
4218 v.push_back (Glib::path_get_basename (oldstr));
4220 old_interchange_dir = Glib::build_filename (v);
4223 v.push_back (newstr);
4224 v.push_back (interchange_dir_name);
4225 v.push_back (legal_name);
4227 new_interchange_dir = Glib::build_filename (v);
4229 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
4231 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
4232 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
4233 old_interchange_dir, new_interchange_dir,
4236 error << string_compose (_("renaming %s as %2 failed (%3)"),
4237 old_interchange_dir, new_interchange_dir,
4246 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
4247 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
4249 cerr << "Rename " << oldstr << " => " << newstr << endl;
4251 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4252 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4253 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4259 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
4261 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
4262 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
4264 cerr << "Rename " << oldstr << " => " << newstr << endl;
4266 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
4267 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
4268 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
4273 /* remove old name from recent sessions */
4274 remove_recent_sessions (_path);
4277 /* update file source paths */
4279 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
4280 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4282 string p = fs->path ();
4283 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
4285 SourceFactory::setup_peakfile(i->second, true);
4289 set_snapshot_name (new_name);
4294 /* save state again to get everything just right */
4296 save_state (_current_snapshot_name);
4298 /* add to recent sessions */
4300 store_recent_sessions (new_name, _path);
4306 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
4308 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
4312 if (!tree.read (xmlpath)) {
4320 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
4323 bool found_sr = false;
4324 bool found_data_format = false;
4326 if (get_session_info_from_path (tree, xmlpath)) {
4332 XMLProperty const * prop;
4333 XMLNode const * root (tree.root());
4335 if ((prop = root->property (X_("sample-rate"))) != 0) {
4336 sample_rate = atoi (prop->value());
4340 const XMLNodeList& children (root->children());
4341 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
4342 const XMLNode* child = *c;
4343 if (child->name() == "Config") {
4344 const XMLNodeList& options (child->children());
4345 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
4346 XMLNode const * option = *oc;
4347 XMLProperty const * name = option->property("name");
4353 if (name->value() == "native-file-data-format") {
4354 XMLProperty const * value = option->property ("value");
4356 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
4358 found_data_format = true;
4364 if (found_data_format) {
4369 return !(found_sr && found_data_format); // zero if they are both found
4373 Session::get_snapshot_from_instant (const std::string& session_dir)
4375 std::string instant_xml_path = Glib::build_filename (session_dir, "instant.xml");
4377 if (!Glib::file_test (instant_xml_path, Glib::FILE_TEST_EXISTS)) {
4382 if (!tree.read (instant_xml_path)) {
4386 XMLProperty const * prop;
4387 XMLNode *last_used_snapshot = tree.root()->child("LastUsedSnapshot");
4388 if (last_used_snapshot && (prop = last_used_snapshot->property ("name")) != 0) {
4389 return prop->value();
4395 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4396 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4399 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4403 SourcePathMap source_path_map;
4405 boost::shared_ptr<AudioFileSource> afs;
4410 Glib::Threads::Mutex::Lock lm (source_lock);
4412 cerr << " total sources = " << sources.size();
4414 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4415 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4421 if (fs->within_session()) {
4425 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4426 source_path_map[fs->path()].push_back (fs);
4428 SeveralFileSources v;
4430 source_path_map.insert (make_pair (fs->path(), v));
4436 cerr << " fsources = " << total << endl;
4438 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4440 /* tell caller where we are */
4442 string old_path = i->first;
4444 callback (n, total, old_path);
4446 cerr << old_path << endl;
4450 switch (i->second.front()->type()) {
4451 case DataType::AUDIO:
4452 new_path = new_audio_source_path_for_embedded (old_path);
4455 case DataType::MIDI:
4456 /* XXX not implemented yet */
4460 if (new_path.empty()) {
4464 cerr << "Move " << old_path << " => " << new_path << endl;
4466 if (!copy_file (old_path, new_path)) {
4467 cerr << "failed !\n";
4471 /* make sure we stop looking in the external
4472 dir/folder. Remember, this is an all-or-nothing
4473 operations, it doesn't merge just some files.
4475 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4477 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4478 (*f)->set_path (new_path);
4483 save_state ("", false, false);
4489 bool accept_all_files (string const &, void *)
4495 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4497 /* 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.
4502 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4504 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4506 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4508 v.push_back (new_session_folder); /* full path */
4509 v.push_back (interchange_dir_name);
4510 v.push_back (new_session_path); /* just one directory/folder */
4511 v.push_back (typedir);
4512 v.push_back (Glib::path_get_basename (old_path));
4514 return Glib::build_filename (v);
4518 Session::save_as (SaveAs& saveas)
4520 vector<string> files;
4521 string current_folder = Glib::path_get_dirname (_path);
4522 string new_folder = legalize_for_path (saveas.new_name);
4523 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4524 int64_t total_bytes = 0;
4528 int32_t internal_file_cnt = 0;
4530 vector<string> do_not_copy_extensions;
4531 do_not_copy_extensions.push_back (statefile_suffix);
4532 do_not_copy_extensions.push_back (pending_suffix);
4533 do_not_copy_extensions.push_back (backup_suffix);
4534 do_not_copy_extensions.push_back (temp_suffix);
4535 do_not_copy_extensions.push_back (history_suffix);
4537 /* get total size */
4539 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4541 /* need to clear this because
4542 * find_files_matching_filter() is cumulative
4547 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4549 all += files.size();
4551 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4553 g_stat ((*i).c_str(), &gsb);
4554 total_bytes += gsb.st_size;
4558 /* save old values so we can switch back if we are not switching to the new session */
4560 string old_path = _path;
4561 string old_name = _name;
4562 string old_snapshot = _current_snapshot_name;
4563 string old_sd = _session_dir->root_path();
4564 vector<string> old_search_path[DataType::num_types];
4565 string old_config_search_path[DataType::num_types];
4567 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4568 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4569 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4570 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4572 /* switch session directory */
4574 (*_session_dir) = to_dir;
4576 /* create new tree */
4578 if (!_session_dir->create()) {
4579 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4584 /* copy all relevant files. Find each location in session_dirs,
4585 * and copy files from there to target.
4588 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4590 /* need to clear this because
4591 * find_files_matching_filter() is cumulative
4596 const size_t prefix_len = (*sd).path.size();
4598 /* Work just on the files within this session dir */
4600 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4602 /* add dir separator to protect against collisions with
4603 * track names (e.g. track named "audiofiles" or
4607 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4608 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4609 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4611 /* copy all the files. Handling is different for media files
4612 than others because of the *silly* subtree we have below the interchange
4613 folder. That really was a bad idea, but I'm not fixing it as part of
4614 implementing ::save_as().
4617 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4619 std::string from = *i;
4622 string filename = Glib::path_get_basename (from);
4623 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4624 if (filename == ".DS_STORE") {
4629 if (from.find (audiofile_dir_string) != string::npos) {
4631 /* audio file: only copy if asked */
4633 if (saveas.include_media && saveas.copy_media) {
4635 string to = make_new_media_path (*i, to_dir, new_folder);
4637 info << "media file copying from " << from << " to " << to << endmsg;
4639 if (!copy_file (from, to)) {
4640 throw Glib::FileError (Glib::FileError::IO_ERROR,
4641 string_compose(_("\ncopying \"%1\" failed !"), from));
4645 /* we found media files inside the session folder */
4647 internal_file_cnt++;
4649 } else if (from.find (midifile_dir_string) != string::npos) {
4651 /* midi file: always copy unless
4652 * creating an empty new session
4655 if (saveas.include_media) {
4657 string to = make_new_media_path (*i, to_dir, new_folder);
4659 info << "media file copying from " << from << " to " << to << endmsg;
4661 if (!copy_file (from, to)) {
4662 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4666 /* we found media files inside the session folder */
4668 internal_file_cnt++;
4670 } else if (from.find (analysis_dir_string) != string::npos) {
4672 /* make sure analysis dir exists in
4673 * new session folder, but we're not
4674 * copying analysis files here, see
4678 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4683 /* normal non-media file. Don't copy state, history, etc.
4686 bool do_copy = true;
4688 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4689 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4690 /* end of filename matches extension, do not copy file */
4696 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4697 /* don't copy peakfiles if
4698 * we're not copying media
4704 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4706 info << "attempting to make directory/folder " << to << endmsg;
4708 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4709 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4712 info << "attempting to copy " << from << " to " << to << endmsg;
4714 if (!copy_file (from, to)) {
4715 throw Glib::FileError (Glib::FileError::IO_ERROR,
4716 string_compose(_("\ncopying \"%1\" failed !"), from));
4721 /* measure file size even if we're not going to copy so that our Progress
4722 signals are correct, since we included these do-not-copy files
4723 in the computation of the total size and file count.
4727 g_stat (from.c_str(), &gsb);
4728 copied += gsb.st_size;
4731 double fraction = (double) copied / total_bytes;
4733 bool keep_going = true;
4735 if (saveas.copy_media) {
4737 /* no need or expectation of this if
4738 * media is not being copied, because
4739 * it will be fast(ish).
4742 /* tell someone "X percent, file M of N"; M is one-based */
4744 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4752 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4758 /* copy optional folders, if any */
4760 string old = plugins_dir ();
4761 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4762 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4763 copy_files (old, newdir);
4766 old = externals_dir ();
4767 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4768 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4769 copy_files (old, newdir);
4772 old = automation_dir ();
4773 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4774 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4775 copy_files (old, newdir);
4778 if (saveas.include_media) {
4780 if (saveas.copy_media) {
4781 #ifndef PLATFORM_WINDOWS
4782 /* There are problems with analysis files on
4783 * Windows, because they used a colon in their
4784 * names as late as 4.0. Colons are not legal
4785 * under Windows even if NTFS allows them.
4787 * This is a tricky problem to solve so for
4788 * just don't copy these files. They will be
4789 * regenerated as-needed anyway, subject to the
4790 * existing issue that the filenames will be
4791 * rejected by Windows, which is a separate
4792 * problem (though related).
4795 /* only needed if we are copying media, since the
4796 * analysis data refers to media data
4799 old = analysis_dir ();
4800 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4801 string newdir = Glib::build_filename (to_dir, "analysis");
4802 copy_files (old, newdir);
4804 #endif /* PLATFORM_WINDOWS */
4810 set_snapshot_name (saveas.new_name);
4811 _name = saveas.new_name;
4813 if (saveas.include_media && !saveas.copy_media) {
4815 /* reset search paths of the new session (which we're pretending to be right now) to
4816 include the original session search path, so we can still find all audio.
4819 if (internal_file_cnt) {
4820 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4821 ensure_search_path_includes (*s, DataType::AUDIO);
4822 cerr << "be sure to include " << *s << " for audio" << endl;
4825 /* we do not do this for MIDI because we copy
4826 all MIDI files if saveas.include_media is
4832 bool was_dirty = dirty ();
4834 save_state ("", false, false, !saveas.include_media);
4835 save_default_options ();
4837 if (saveas.copy_media && saveas.copy_external) {
4838 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4839 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4843 saveas.final_session_folder_name = _path;
4845 store_recent_sessions (_name, _path);
4847 if (!saveas.switch_to) {
4849 /* switch back to the way things were */
4853 set_snapshot_name (old_snapshot);
4855 (*_session_dir) = old_sd;
4861 if (internal_file_cnt) {
4862 /* reset these to their original values */
4863 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4864 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4869 /* prune session dirs, and update disk space statistics
4874 session_dirs.clear ();
4875 session_dirs.push_back (sp);
4876 refresh_disk_space ();
4878 /* ensure that all existing tracks reset their current capture source paths
4880 reset_write_sources (true, true);
4882 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4883 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4886 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4887 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4893 if (fs->within_session()) {
4894 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4895 fs->set_path (newpath);
4900 } catch (Glib::FileError& e) {
4902 saveas.failure_message = e.what();
4904 /* recursively remove all the directories */
4906 remove_directory (to_dir);
4914 saveas.failure_message = _("unknown reason");
4916 /* recursively remove all the directories */
4918 remove_directory (to_dir);
4928 static void set_progress (Progress* p, size_t n, size_t t)
4930 p->set_progress (float (n) / float(t));
4934 Session::archive_session (const std::string& dest,
4935 const std::string& name,
4936 ArchiveEncode compress_audio,
4937 bool only_used_sources,
4940 if (dest.empty () || name.empty ()) {
4944 /* save current values */
4945 bool was_dirty = dirty ();
4946 string old_path = _path;
4947 string old_name = _name;
4948 string old_snapshot = _current_snapshot_name;
4949 string old_sd = _session_dir->root_path();
4950 string old_config_search_path[DataType::num_types];
4951 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4952 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4954 /* ensure that session-path is included in search-path */
4956 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4957 if ((*sd).path == old_path) {
4965 /* create temporary dir to save session to */
4966 #ifdef PLATFORM_WINDOWS
4967 char tmp[256] = "C:\\TEMP\\";
4968 GetTempPath (sizeof (tmp), tmp);
4970 char const* tmp = getenv("TMPDIR");
4975 if ((strlen (tmp) + 21) > 1024) {
4980 strcpy (tmptpl, tmp);
4981 strcat (tmptpl, "ardourarchive-XXXXXX");
4982 char* tmpdir = g_mkdtemp (tmptpl);
4988 std::string to_dir = std::string (tmpdir);
4990 /* switch session directory temporarily */
4991 (*_session_dir) = to_dir;
4993 if (!_session_dir->create()) {
4994 (*_session_dir) = old_sd;
4995 remove_directory (to_dir);
4999 /* prepare archive */
5000 string archive = Glib::build_filename (dest, name + ".tar.xz");
5002 PBD::ScopedConnectionList progress_connection;
5003 PBD::FileArchive ar (archive);
5005 ar.progress.connect_same_thread (progress_connection, boost::bind (&set_progress, progress, _1, _2));
5008 /* collect files to archive */
5009 std::map<string,string> filemap;
5011 vector<string> do_not_copy_extensions;
5012 do_not_copy_extensions.push_back (statefile_suffix);
5013 do_not_copy_extensions.push_back (pending_suffix);
5014 do_not_copy_extensions.push_back (backup_suffix);
5015 do_not_copy_extensions.push_back (temp_suffix);
5016 do_not_copy_extensions.push_back (history_suffix);
5018 vector<string> blacklist_dirs;
5019 blacklist_dirs.push_back (string (peak_dir_name) + G_DIR_SEPARATOR);
5020 blacklist_dirs.push_back (string (analysis_dir_name) + G_DIR_SEPARATOR);
5021 blacklist_dirs.push_back (string (dead_dir_name) + G_DIR_SEPARATOR);
5022 blacklist_dirs.push_back (string (export_dir_name) + G_DIR_SEPARATOR);
5023 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5024 blacklist_dirs.push_back (string (plugins_dir_name) + G_DIR_SEPARATOR);
5026 std::map<boost::shared_ptr<AudioFileSource>, std::string> orig_sources;
5028 set<boost::shared_ptr<Source> > sources_used_by_this_snapshot;
5029 if (only_used_sources) {
5030 playlists->sync_all_regions_with_regions ();
5031 playlists->foreach (boost::bind (merge_all_sources, _1, &sources_used_by_this_snapshot), false);
5034 // collect audio sources for this session, calc total size for encoding
5035 // add option to only include *used* sources (see Session::cleanup_sources)
5036 size_t total_size = 0;
5038 Glib::Threads::Mutex::Lock lm (source_lock);
5039 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5040 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5041 if (!afs || afs->readable_length () == 0) {
5045 if (only_used_sources) {
5049 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5054 std::string from = afs->path();
5056 if (compress_audio != NO_ENCODE) {
5057 total_size += afs->readable_length ();
5059 if (afs->within_session()) {
5060 filemap[from] = make_new_media_path (from, name, name);
5062 filemap[from] = make_new_media_path (from, name, name);
5063 remove_dir_from_search_path (Glib::path_get_dirname (from), DataType::AUDIO);
5070 if (compress_audio != NO_ENCODE) {
5072 progress->set_progress (2); // set to "encoding"
5073 progress->set_progress (0);
5076 Glib::Threads::Mutex::Lock lm (source_lock);
5077 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
5078 boost::shared_ptr<AudioFileSource> afs = boost::dynamic_pointer_cast<AudioFileSource> (i->second);
5079 if (!afs || afs->readable_length () == 0) {
5083 if (only_used_sources) {
5087 if (sources_used_by_this_snapshot.find (afs) == sources_used_by_this_snapshot.end ()) {
5092 orig_sources[afs] = afs->path();
5094 std::string new_path = make_new_media_path (afs->path (), to_dir, name);
5095 new_path = Glib::build_filename (Glib::path_get_dirname (new_path), PBD::basename_nosuffix (new_path) + ".flac");
5096 g_mkdir_with_parents (Glib::path_get_dirname (new_path).c_str (), 0755);
5099 progress->descend ((float)afs->readable_length () / total_size);
5103 SndFileSource* ns = new SndFileSource (*this, *(afs.get()), new_path, compress_audio == FLAC_16BIT, progress);
5104 afs->replace_file (new_path);
5107 cerr << "failed to encode " << afs->path() << " to " << new_path << "\n";
5111 progress->ascend ();
5117 progress->set_progress (-1); // set to "archiving"
5118 progress->set_progress (0);
5121 /* index files relevant for this session */
5122 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
5123 vector<string> files;
5125 size_t prefix_len = (*sd).path.size();
5126 if (prefix_len > 0 && (*sd).path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5130 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
5132 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
5133 static const std::string videofile_dir_string = string (video_dir_name) + G_DIR_SEPARATOR;
5134 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
5136 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5137 std::string from = *i;
5140 string filename = Glib::path_get_basename (from);
5141 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
5142 if (filename == ".DS_STORE") {
5147 if (from.find (audiofile_dir_string) != string::npos) {
5149 } else if (from.find (midifile_dir_string) != string::npos) {
5150 filemap[from] = make_new_media_path (from, name, name);
5151 } else if (from.find (videofile_dir_string) != string::npos) {
5152 filemap[from] = make_new_media_path (from, name, name);
5154 bool do_copy = true;
5155 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5156 if (from.find (*v) != string::npos) {
5161 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5162 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5169 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5175 /* write session file */
5177 g_mkdir_with_parents (externals_dir ().c_str (), 0755);
5179 PBD::Unwinder<bool> uw (LV2Plugin::force_state_save, true);
5181 save_default_options ();
5183 size_t prefix_len = _path.size();
5184 if (prefix_len > 0 && _path.at (prefix_len - 1) != G_DIR_SEPARATOR) {
5188 /* collect session-state files */
5189 vector<string> files;
5190 do_not_copy_extensions.clear ();
5191 do_not_copy_extensions.push_back (history_suffix);
5193 blacklist_dirs.clear ();
5194 blacklist_dirs.push_back (string (externals_dir_name) + G_DIR_SEPARATOR);
5196 find_files_matching_filter (files, to_dir, accept_all_files, 0, false, true, true);
5197 for (vector<string>::const_iterator i = files.begin (); i != files.end (); ++i) {
5198 std::string from = *i;
5199 bool do_copy = true;
5200 for (vector<string>::iterator v = blacklist_dirs.begin(); v != blacklist_dirs.end(); ++v) {
5201 if (from.find (*v) != string::npos) {
5206 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
5207 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
5213 filemap[from] = name + G_DIR_SEPARATOR + from.substr (prefix_len);
5217 /* restore original values */
5220 set_snapshot_name (old_snapshot);
5221 (*_session_dir) = old_sd;
5225 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
5226 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
5228 for (std::map<boost::shared_ptr<AudioFileSource>, std::string>::iterator i = orig_sources.begin (); i != orig_sources.end (); ++i) {
5229 i->first->replace_file (i->second);
5232 int rv = ar.create (filemap);
5233 remove_directory (to_dir);
5239 Session::undo (uint32_t n)
5241 if (actively_recording()) {
5249 Session::redo (uint32_t n)
5251 if (actively_recording()) {