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"
31 #include <cstdio> /* snprintf(3) ... grrr */
44 #include <sys/param.h>
45 #include <sys/mount.h>
48 #ifdef HAVE_SYS_STATVFS_H
49 #include <sys/statvfs.h>
53 #include <glib/gstdio.h>
56 #include <glibmm/threads.h>
57 #include <glibmm/fileutils.h>
59 #include <boost/algorithm/string.hpp>
61 #include "midi++/mmc.h"
62 #include "midi++/port.h"
64 #include "evoral/SMF.hpp"
66 #include "pbd/boost_debug.h"
67 #include "pbd/basename.h"
68 #include "pbd/controllable_descriptor.h"
69 #include "pbd/enumwriter.h"
70 #include "pbd/error.h"
71 #include "pbd/file_utils.h"
72 #include "pbd/pathexpand.h"
73 #include "pbd/pthread_utils.h"
74 #include "pbd/stacktrace.h"
75 #include "pbd/convert.h"
76 #include "pbd/localtime_r.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/automation_control.h"
86 #include "ardour/butler.h"
87 #include "ardour/control_protocol_manager.h"
88 #include "ardour/directory_names.h"
89 #include "ardour/filename_extensions.h"
90 #include "ardour/graph.h"
91 #include "ardour/location.h"
92 #include "ardour/midi_model.h"
93 #include "ardour/midi_patch_manager.h"
94 #include "ardour/midi_region.h"
95 #include "ardour/midi_scene_changer.h"
96 #include "ardour/midi_source.h"
97 #include "ardour/midi_track.h"
98 #include "ardour/pannable.h"
99 #include "ardour/playlist_factory.h"
100 #include "ardour/playlist_source.h"
101 #include "ardour/port.h"
102 #include "ardour/processor.h"
103 #include "ardour/profile.h"
104 #include "ardour/proxy_controllable.h"
105 #include "ardour/recent_sessions.h"
106 #include "ardour/region_factory.h"
107 #include "ardour/route_group.h"
108 #include "ardour/send.h"
109 #include "ardour/session.h"
110 #include "ardour/session_directory.h"
111 #include "ardour/session_metadata.h"
112 #include "ardour/session_playlists.h"
113 #include "ardour/session_state_utils.h"
114 #include "ardour/silentfilesource.h"
115 #include "ardour/sndfilesource.h"
116 #include "ardour/source_factory.h"
117 #include "ardour/speakers.h"
118 #include "ardour/template_utils.h"
119 #include "ardour/tempo.h"
120 #include "ardour/ticker.h"
121 #include "ardour/user_bundle.h"
123 #include "control_protocol/control_protocol.h"
129 using namespace ARDOUR;
133 Session::pre_engine_init (string fullpath)
135 if (fullpath.empty()) {
137 throw failed_constructor();
140 /* discover canonical fullpath */
142 _path = canonical_path(fullpath);
146 _is_new = !Glib::file_test (_path, Glib::FileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR));
148 /* finish initialization that can't be done in a normal C++ constructor
152 timerclear (&last_mmc_step);
153 g_atomic_int_set (&processing_prohibited, 0);
154 g_atomic_int_set (&_record_status, Disabled);
155 g_atomic_int_set (&_playback_load, 100);
156 g_atomic_int_set (&_capture_load, 100);
158 _all_route_group->set_active (true, this);
159 interpolation.add_channel_to (0, 0);
161 if (config.get_use_video_sync()) {
162 waiting_for_sync_offset = true;
164 waiting_for_sync_offset = false;
167 last_rr_session_dir = session_dirs.begin();
169 set_history_depth (Config->get_history_depth());
171 /* default: assume simple stereo speaker configuration */
173 _speakers->setup_default_speakers (2);
175 _solo_cut_control.reset (new ProxyControllable (_("solo cut control (dB)"), PBD::Controllable::GainLike,
176 boost::bind (&RCConfiguration::set_solo_mute_gain, Config, _1),
177 boost::bind (&RCConfiguration::get_solo_mute_gain, Config)));
178 add_controllable (_solo_cut_control);
180 /* These are all static "per-class" signals */
182 SourceFactory::SourceCreated.connect_same_thread (*this, boost::bind (&Session::add_source, this, _1));
183 PlaylistFactory::PlaylistCreated.connect_same_thread (*this, boost::bind (&Session::add_playlist, this, _1, _2));
184 AutomationList::AutomationListCreated.connect_same_thread (*this, boost::bind (&Session::add_automation_list, this, _1));
185 Controllable::Destroyed.connect_same_thread (*this, boost::bind (&Session::remove_controllable, this, _1));
186 IO::PortCountChanged.connect_same_thread (*this, boost::bind (&Session::ensure_buffers, this, _1));
188 /* stop IO objects from doing stuff until we're ready for them */
190 Delivery::disable_panners ();
191 IO::disable_connecting ();
193 AudioFileSource::set_peak_dir (_session_dir->peak_path());
197 Session::post_engine_init ()
199 BootMessage (_("Set block size and sample rate"));
201 set_block_size (_engine.samples_per_cycle());
202 set_frame_rate (_engine.sample_rate());
204 BootMessage (_("Using configuration"));
206 _midi_ports = new MidiPortManager;
208 MIDISceneChanger* msc;
210 _scene_changer = msc = new MIDISceneChanger (*this);
211 msc->set_input_port (scene_input_port());
212 msc->set_output_port (scene_out());
214 boost::function<framecnt_t(void)> timer_func (boost::bind (&Session::audible_frame, this));
215 boost::dynamic_pointer_cast<AsyncMIDIPort>(scene_in())->set_timer (timer_func);
217 setup_midi_machine_control ();
219 if (_butler->start_thread()) {
223 if (start_midi_thread ()) {
227 setup_click_sounds (0);
228 setup_midi_control ();
230 _engine.Halted.connect_same_thread (*this, boost::bind (&Session::engine_halted, this));
231 _engine.Xrun.connect_same_thread (*this, boost::bind (&Session::xrun_recovery, this));
234 /* tempo map requires sample rate knowledge */
237 _tempo_map = new TempoMap (_current_frame_rate);
238 _tempo_map->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::tempo_map_changed, this, _1));
240 /* MidiClock requires a tempo map */
242 midi_clock = new MidiClockTicker ();
243 midi_clock->set_session (this);
245 /* crossfades require sample rate knowledge */
247 SndFileSource::setup_standard_crossfades (*this, frame_rate());
248 _engine.GraphReordered.connect_same_thread (*this, boost::bind (&Session::graph_reordered, this));
250 AudioDiskstream::allocate_working_buffers();
251 refresh_disk_space ();
253 /* we're finally ready to call set_state() ... all objects have
254 * been created, the engine is running.
258 if (set_state (*state_tree->root(), Stateful::loading_state_version)) {
262 // set_state() will call setup_raid_path(), but if it's a new session we need
263 // to call setup_raid_path() here.
264 setup_raid_path (_path);
269 boost::function<void (std::string)> ff (boost::bind (&Session::config_changed, this, _1, false));
270 boost::function<void (std::string)> ft (boost::bind (&Session::config_changed, this, _1, true));
272 Config->map_parameters (ff);
273 config.map_parameters (ft);
275 /* Reset all panners */
277 Delivery::reset_panners ();
279 /* this will cause the CPM to instantiate any protocols that are in use
280 * (or mandatory), which will pass it this Session, and then call
281 * set_state() on each instantiated protocol to match stored state.
284 ControlProtocolManager::instance().set_session (this);
286 /* This must be done after the ControlProtocolManager set_session above,
287 as it will set states for ports which the ControlProtocolManager creates.
290 // XXX set state of MIDI::Port's
291 // MidiPortManager::instance()->set_port_states (Config->midi_port_states ());
293 /* And this must be done after the MIDI::Manager::set_port_states as
294 * it will try to make connections whose details are loaded by set_port_states.
299 /* Let control protocols know that we are now all connected, so they
300 * could start talking to surfaces if they want to.
303 ControlProtocolManager::instance().midi_connectivity_established ();
305 if (_is_new && !no_auto_connect()) {
306 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock());
307 auto_connect_master_bus ();
310 _state_of_the_state = StateOfTheState (_state_of_the_state & ~(CannotSave|Dirty));
312 /* update latencies */
314 initialize_latencies ();
316 _locations->added.connect_same_thread (*this, boost::bind (&Session::location_added, this, _1));
317 _locations->removed.connect_same_thread (*this, boost::bind (&Session::location_removed, this, _1));
318 _locations->changed.connect_same_thread (*this, boost::bind (&Session::locations_changed, this));
320 } catch (AudioEngine::PortRegistrationFailure& err) {
321 /* handle this one in a different way than all others, so that its clear what happened */
322 error << err.what() << endmsg;
328 BootMessage (_("Reset Remote Controls"));
330 // send_full_time_code (0);
331 _engine.transport_locate (0);
333 send_immediate_mmc (MIDI::MachineControlCommand (MIDI::MachineControl::cmdMmcReset));
334 send_immediate_mmc (MIDI::MachineControlCommand (Timecode::Time ()));
336 MIDI::Name::MidiPatchManager::instance().set_session (this);
339 /* initial program change will be delivered later; see ::config_changed() */
341 _state_of_the_state = Clean;
343 Port::set_connecting_blocked (false);
345 DirtyChanged (); /* EMIT SIGNAL */
349 } else if (state_was_pending) {
351 remove_pending_capture_state ();
352 state_was_pending = false;
359 Session::session_loaded ()
363 _state_of_the_state = Clean;
365 DirtyChanged (); /* EMIT SIGNAL */
369 } else if (state_was_pending) {
371 remove_pending_capture_state ();
372 state_was_pending = false;
375 /* Now, finally, we can fill the playback buffers */
377 BootMessage (_("Filling playback buffers"));
379 boost::shared_ptr<RouteList> rl = routes.reader();
380 for (RouteList::iterator r = rl->begin(); r != rl->end(); ++r) {
381 boost::shared_ptr<Track> trk = boost::dynamic_pointer_cast<Track> (*r);
382 if (trk && !trk->hidden()) {
383 trk->seek (_transport_frame, true);
389 Session::raid_path () const
391 Searchpath raid_search_path;
393 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
394 raid_search_path += (*i).path;
397 return raid_search_path.to_string ();
401 Session::setup_raid_path (string path)
410 session_dirs.clear ();
412 Searchpath search_path(path);
413 Searchpath sound_search_path;
414 Searchpath midi_search_path;
416 for (Searchpath::const_iterator i = search_path.begin(); i != search_path.end(); ++i) {
418 sp.blocks = 0; // not needed
419 session_dirs.push_back (sp);
421 SessionDirectory sdir(sp.path);
423 sound_search_path += sdir.sound_path ();
424 midi_search_path += sdir.midi_path ();
427 // reset the round-robin soundfile path thingie
428 last_rr_session_dir = session_dirs.begin();
432 Session::path_is_within_session (const std::string& path)
434 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
435 if (PBD::path_is_within (i->path, path)) {
443 Session::ensure_subdirs ()
447 dir = session_directory().peak_path();
449 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
450 error << string_compose(_("Session: cannot create session peakfile folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
454 dir = session_directory().sound_path();
456 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
457 error << string_compose(_("Session: cannot create session sounds dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
461 dir = session_directory().midi_path();
463 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
464 error << string_compose(_("Session: cannot create session midi dir \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
468 dir = session_directory().dead_path();
470 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
471 error << string_compose(_("Session: cannot create session dead sounds folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
475 dir = session_directory().export_path();
477 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
478 error << string_compose(_("Session: cannot create session export folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
482 dir = analysis_dir ();
484 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
485 error << string_compose(_("Session: cannot create session analysis folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
489 dir = plugins_dir ();
491 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
492 error << string_compose(_("Session: cannot create session plugins folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
496 dir = externals_dir ();
498 if (g_mkdir_with_parents (dir.c_str(), 0755) < 0) {
499 error << string_compose(_("Session: cannot create session externals folder \"%1\" (%2)"), dir, strerror (errno)) << endmsg;
506 /** @param session_template directory containing session template, or empty.
507 * Caller must not hold process lock.
510 Session::create (const string& session_template, BusProfile* bus_profile)
512 if (g_mkdir_with_parents (_path.c_str(), 0755) < 0) {
513 error << string_compose(_("Session: cannot create session folder \"%1\" (%2)"), _path, strerror (errno)) << endmsg;
517 if (ensure_subdirs ()) {
521 _writable = exists_and_writable (_path);
523 if (!session_template.empty()) {
524 std::string in_path = (ARDOUR::Profile->get_trx () ? session_template : session_template_dir_to_file (session_template));
526 ifstream in(in_path.c_str());
529 /* no need to call legalize_for_path() since the string
530 * in session_template is already a legal path name
532 string out_path = Glib::build_filename (_session_dir->root_path(), _name + statefile_suffix);
534 ofstream out(out_path.c_str());
540 if (!ARDOUR::Profile->get_trx()) {
541 /* Copy plugin state files from template to new session */
542 std::string template_plugins = Glib::build_filename (session_template, X_("plugins"));
543 copy_recurse (template_plugins, plugins_dir ());
549 error << string_compose (_("Could not open %1 for writing session template"), out_path)
555 error << string_compose (_("Could not open session template %1 for reading"), in_path)
562 /* set initial start + end point */
564 _state_of_the_state = Clean;
566 /* set up Master Out and Control Out if necessary */
571 ChanCount count(DataType::AUDIO, bus_profile->master_out_channels);
573 // Waves Tracks: always create master bus for Tracks
574 if (ARDOUR::Profile->get_trx() || bus_profile->master_out_channels) {
575 boost::shared_ptr<Route> r (new Route (*this, _("Master"), Route::MasterOut, DataType::AUDIO));
579 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
580 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
583 Glib::Threads::Mutex::Lock lm (AudioEngine::instance()->process_lock ());
584 r->input()->ensure_io (count, false, this);
585 r->output()->ensure_io (count, false, this);
591 /* prohibit auto-connect to master, because there isn't one */
592 bus_profile->output_ac = AutoConnectOption (bus_profile->output_ac & ~AutoConnectMaster);
596 add_routes (rl, false, false, false);
599 // Waves Tracks: Skip this. Always use autoconnection for Tracks
600 if (!ARDOUR::Profile->get_trx()) {
602 /* this allows the user to override settings with an environment variable.
605 if (no_auto_connect()) {
606 bus_profile->input_ac = AutoConnectOption (0);
607 bus_profile->output_ac = AutoConnectOption (0);
610 Config->set_input_auto_connect (bus_profile->input_ac);
611 Config->set_output_auto_connect (bus_profile->output_ac);
615 if (Config->get_use_monitor_bus() && bus_profile) {
616 add_monitor_section ();
623 Session::maybe_write_autosave()
625 if (dirty() && record_status() != Recording) {
626 save_state("", true);
631 Session::remove_pending_capture_state ()
633 std::string pending_state_file_path(_session_dir->root_path());
635 pending_state_file_path = Glib::build_filename (pending_state_file_path, legalize_for_path (_current_snapshot_name) + pending_suffix);
637 if (!Glib::file_test (pending_state_file_path, Glib::FILE_TEST_EXISTS)) return;
639 if (g_remove (pending_state_file_path.c_str()) != 0) {
640 error << string_compose(_("Could not remove pending capture state at path \"%1\" (%2)"),
641 pending_state_file_path, g_strerror (errno)) << endmsg;
645 /** Rename a state file.
646 * @param old_name Old snapshot name.
647 * @param new_name New snapshot name.
650 Session::rename_state (string old_name, string new_name)
652 if (old_name == _current_snapshot_name || old_name == _name) {
653 /* refuse to rename the current snapshot or the "main" one */
657 const string old_xml_filename = legalize_for_path (old_name) + statefile_suffix;
658 const string new_xml_filename = legalize_for_path (new_name) + statefile_suffix;
660 const std::string old_xml_path(Glib::build_filename (_session_dir->root_path(), old_xml_filename));
661 const std::string new_xml_path(Glib::build_filename (_session_dir->root_path(), new_xml_filename));
663 if (::g_rename (old_xml_path.c_str(), new_xml_path.c_str()) != 0) {
664 error << string_compose(_("could not rename snapshot %1 to %2 (%3)"),
665 old_name, new_name, g_strerror(errno)) << endmsg;
669 /** Remove a state file.
670 * @param snapshot_name Snapshot name.
673 Session::remove_state (string snapshot_name)
675 if (!_writable || snapshot_name == _current_snapshot_name || snapshot_name == _name) {
676 // refuse to remove the current snapshot or the "main" one
680 std::string xml_path(_session_dir->root_path());
682 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
684 if (!create_backup_file (xml_path)) {
685 // don't remove it if a backup can't be made
686 // create_backup_file will log the error.
691 if (g_remove (xml_path.c_str()) != 0) {
692 error << string_compose(_("Could not remove session file at path \"%1\" (%2)"),
693 xml_path, g_strerror (errno)) << endmsg;
697 /** @param snapshot_name Name to save under, without .ardour / .pending prefix */
699 Session::save_state (string snapshot_name, bool pending, bool switch_to_snapshot, bool template_only)
702 std::string xml_path(_session_dir->root_path());
704 /* prevent concurrent saves from different threads */
706 Glib::Threads::Mutex::Lock lm (save_state_lock);
708 if (!_writable || (_state_of_the_state & CannotSave)) {
712 if (g_atomic_int_get(&_suspend_save)) {
716 _save_queued = false;
718 if (!_engine.connected ()) {
719 error << string_compose (_("the %1 audio engine is not connected and state saving would lose all I/O connections. Session not saved"),
725 /* tell sources we're saving first, in case they write out to a new file
726 * which should be saved with the state rather than the old one */
727 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
729 i->second->session_saved();
730 } catch (Evoral::SMF::FileError& e) {
731 error << string_compose ("Could not write to MIDI file %1; MIDI data not saved.", e.file_name ()) << endmsg;
735 SessionSaveUnderway (); /* EMIT SIGNAL */
738 tree.set_root (&get_template());
740 tree.set_root (&get_state());
743 if (snapshot_name.empty()) {
744 snapshot_name = _current_snapshot_name;
745 } else if (switch_to_snapshot) {
746 _current_snapshot_name = snapshot_name;
751 /* proper save: use statefile_suffix (.ardour in English) */
753 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + statefile_suffix);
755 /* make a backup copy of the old file */
757 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS) && !create_backup_file (xml_path)) {
758 // create_backup_file will log the error
764 /* pending save: use pending_suffix (.pending in English) */
765 xml_path = Glib::build_filename (xml_path, legalize_for_path (snapshot_name) + pending_suffix);
768 std::string tmp_path(_session_dir->root_path());
769 tmp_path = Glib::build_filename (tmp_path, legalize_for_path (snapshot_name) + temp_suffix);
771 cerr << "actually writing state to " << tmp_path << endl;
773 if (!tree.write (tmp_path)) {
774 error << string_compose (_("state could not be saved to %1"), tmp_path) << endmsg;
775 if (g_remove (tmp_path.c_str()) != 0) {
776 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
777 tmp_path, g_strerror (errno)) << endmsg;
783 cerr << "renaming state to " << xml_path << endl;
785 if (::g_rename (tmp_path.c_str(), xml_path.c_str()) != 0) {
786 error << string_compose (_("could not rename temporary session file %1 to %2 (%3)"),
787 tmp_path, xml_path, g_strerror(errno)) << endmsg;
788 if (g_remove (tmp_path.c_str()) != 0) {
789 error << string_compose(_("Could not remove temporary session file at path \"%1\" (%2)"),
790 tmp_path, g_strerror (errno)) << endmsg;
798 save_history (snapshot_name);
800 bool was_dirty = dirty();
802 _state_of_the_state = StateOfTheState (_state_of_the_state & ~Dirty);
805 DirtyChanged (); /* EMIT SIGNAL */
808 StateSaved (snapshot_name); /* EMIT SIGNAL */
815 Session::restore_state (string snapshot_name)
817 if (load_state (snapshot_name) == 0) {
818 set_state (*state_tree->root(), Stateful::loading_state_version);
825 Session::load_state (string snapshot_name)
830 state_was_pending = false;
832 /* check for leftover pending state from a crashed capture attempt */
834 std::string xmlpath(_session_dir->root_path());
835 xmlpath = Glib::build_filename (xmlpath, legalize_for_path (snapshot_name) + pending_suffix);
837 if (Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
839 /* there is pending state from a crashed capture attempt */
841 boost::optional<int> r = AskAboutPendingState();
842 if (r.get_value_or (1)) {
843 state_was_pending = true;
847 if (!state_was_pending) {
848 xmlpath = Glib::build_filename (_session_dir->root_path(), snapshot_name);
851 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
852 xmlpath = Glib::build_filename (_session_dir->root_path(), legalize_for_path (snapshot_name) + statefile_suffix);
853 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
854 error << string_compose(_("%1: session file \"%2\" doesn't exist!"), _name, xmlpath) << endmsg;
859 state_tree = new XMLTree;
863 _writable = exists_and_writable (xmlpath) && exists_and_writable(Glib::path_get_dirname(xmlpath));
865 if (!state_tree->read (xmlpath)) {
866 error << string_compose(_("Could not understand session file %1"), xmlpath) << endmsg;
872 XMLNode& root (*state_tree->root());
874 if (root.name() != X_("Session")) {
875 error << string_compose (_("Session file %1 is not a session"), xmlpath) << endmsg;
881 const XMLProperty* prop;
883 if ((prop = root.property ("version")) == 0) {
884 /* no version implies very old version of Ardour */
885 Stateful::loading_state_version = 1000;
887 if (prop->value().find ('.') != string::npos) {
888 /* old school version format */
889 if (prop->value()[0] == '2') {
890 Stateful::loading_state_version = 2000;
892 Stateful::loading_state_version = 3000;
895 Stateful::loading_state_version = atoi (prop->value());
899 if (Stateful::loading_state_version < CURRENT_SESSION_FILE_VERSION && _writable) {
901 std::string backup_path(_session_dir->root_path());
902 std::string backup_filename = string_compose ("%1-%2%3", legalize_for_path (snapshot_name), Stateful::loading_state_version, statefile_suffix);
903 backup_path = Glib::build_filename (backup_path, backup_filename);
905 // only create a backup for a given statefile version once
907 if (!Glib::file_test (backup_path, Glib::FILE_TEST_EXISTS)) {
909 VersionMismatch (xmlpath, backup_path);
911 if (!copy_file (xmlpath, backup_path)) {;
921 Session::load_options (const XMLNode& node)
923 LocaleGuard lg (X_("C"));
924 config.set_variables (node);
929 Session::save_default_options ()
931 return config.save_state();
941 Session::get_template()
943 /* if we don't disable rec-enable, diskstreams
944 will believe they need to store their capture
945 sources in their state node.
948 disable_record (false);
954 Session::state (bool full_state)
956 XMLNode* node = new XMLNode("Session");
960 snprintf(buf, sizeof(buf), "%d", CURRENT_SESSION_FILE_VERSION);
961 node->add_property("version", buf);
963 /* store configuration settings */
967 node->add_property ("name", _name);
968 snprintf (buf, sizeof (buf), "%" PRId64, _nominal_frame_rate);
969 node->add_property ("sample-rate", buf);
971 if (session_dirs.size() > 1) {
975 vector<space_and_path>::iterator i = session_dirs.begin();
976 vector<space_and_path>::iterator next;
978 ++i; /* skip the first one */
982 while (i != session_dirs.end()) {
986 if (next != session_dirs.end()) {
987 p += G_SEARCHPATH_SEPARATOR;
996 child = node->add_child ("Path");
997 child->add_content (p);
1001 /* save the ID counter */
1003 snprintf (buf, sizeof (buf), "%" PRIu64, ID::counter());
1004 node->add_property ("id-counter", buf);
1006 /* save the event ID counter */
1008 snprintf (buf, sizeof (buf), "%d", Evoral::event_id_counter());
1009 node->add_property ("event-counter", buf);
1011 /* various options */
1013 list<XMLNode*> midi_port_nodes = _midi_ports->get_midi_port_states();
1014 if (!midi_port_nodes.empty()) {
1015 XMLNode* midi_port_stuff = new XMLNode ("MIDIPorts");
1016 for (list<XMLNode*>::const_iterator n = midi_port_nodes.begin(); n != midi_port_nodes.end(); ++n) {
1017 midi_port_stuff->add_child_nocopy (**n);
1019 node->add_child_nocopy (*midi_port_stuff);
1022 node->add_child_nocopy (config.get_variables ());
1024 node->add_child_nocopy (ARDOUR::SessionMetadata::Metadata()->get_state());
1026 child = node->add_child ("Sources");
1029 Glib::Threads::Mutex::Lock sl (source_lock);
1031 for (SourceMap::iterator siter = sources.begin(); siter != sources.end(); ++siter) {
1033 /* Don't save information about non-file Sources, or
1034 * about non-destructive file sources that are empty
1035 * and unused by any regions.
1038 boost::shared_ptr<FileSource> fs;
1040 if ((fs = boost::dynamic_pointer_cast<FileSource> (siter->second)) != 0) {
1042 if (!fs->destructive()) {
1043 if (fs->empty() && !fs->used()) {
1048 child->add_child_nocopy (siter->second->get_state());
1053 child = node->add_child ("Regions");
1056 Glib::Threads::Mutex::Lock rl (region_lock);
1057 const RegionFactory::RegionMap& region_map (RegionFactory::all_regions());
1058 for (RegionFactory::RegionMap::const_iterator i = region_map.begin(); i != region_map.end(); ++i) {
1059 boost::shared_ptr<Region> r = i->second;
1060 /* only store regions not attached to playlists */
1061 if (r->playlist() == 0) {
1062 if (boost::dynamic_pointer_cast<AudioRegion>(r)) {
1063 child->add_child_nocopy ((boost::dynamic_pointer_cast<AudioRegion>(r))->get_basic_state ());
1065 child->add_child_nocopy (r->get_state ());
1070 RegionFactory::CompoundAssociations& cassocs (RegionFactory::compound_associations());
1072 if (!cassocs.empty()) {
1073 XMLNode* ca = node->add_child (X_("CompoundAssociations"));
1075 for (RegionFactory::CompoundAssociations::iterator i = cassocs.begin(); i != cassocs.end(); ++i) {
1077 XMLNode* can = new XMLNode (X_("CompoundAssociation"));
1078 i->first->id().print (buf, sizeof (buf));
1079 can->add_property (X_("copy"), buf);
1080 i->second->id().print (buf, sizeof (buf));
1081 can->add_property (X_("original"), buf);
1082 ca->add_child_nocopy (*can);
1092 node->add_child_nocopy (_locations->get_state());
1095 Locations loc (*this);
1096 // for a template, just create a new Locations, populate it
1097 // with the default start and end, and get the state for that.
1098 Location* range = new Location (*this, 0, 0, _("session"), Location::IsSessionRange);
1099 range->set (max_framepos, 0);
1101 XMLNode& locations_state = loc.get_state();
1103 if (ARDOUR::Profile->get_trx() && _locations) {
1104 for (Locations::LocationList::const_iterator i = _locations->list ().begin (); i != _locations->list ().end (); ++i) {
1105 if ((*i)->is_mark () || (*i)->is_auto_loop ()) {
1106 locations_state.add_child_nocopy ((*i)->get_state ());
1110 node->add_child_nocopy (locations_state);
1113 child = node->add_child ("Bundles");
1115 boost::shared_ptr<BundleList> bundles = _bundles.reader ();
1116 for (BundleList::iterator i = bundles->begin(); i != bundles->end(); ++i) {
1117 boost::shared_ptr<UserBundle> b = boost::dynamic_pointer_cast<UserBundle> (*i);
1119 child->add_child_nocopy (b->get_state());
1124 child = node->add_child ("Routes");
1126 boost::shared_ptr<RouteList> r = routes.reader ();
1128 RoutePublicOrderSorter cmp;
1129 RouteList public_order (*r);
1130 public_order.sort (cmp);
1132 /* the sort should have put control outs first */
1135 assert (_monitor_out == public_order.front());
1138 for (RouteList::iterator i = public_order.begin(); i != public_order.end(); ++i) {
1139 if (!(*i)->is_auditioner()) {
1141 child->add_child_nocopy ((*i)->get_state());
1143 child->add_child_nocopy ((*i)->get_template());
1149 playlists->add_state (node, full_state);
1151 child = node->add_child ("RouteGroups");
1152 for (list<RouteGroup *>::iterator i = _route_groups.begin(); i != _route_groups.end(); ++i) {
1153 child->add_child_nocopy ((*i)->get_state());
1157 XMLNode* gain_child = node->add_child ("Click");
1158 gain_child->add_child_nocopy (_click_io->state (full_state));
1159 gain_child->add_child_nocopy (_click_gain->state (full_state));
1163 XMLNode* ltc_input_child = node->add_child ("LTC-In");
1164 ltc_input_child->add_child_nocopy (_ltc_input->state (full_state));
1168 XMLNode* ltc_output_child = node->add_child ("LTC-Out");
1169 ltc_output_child->add_child_nocopy (_ltc_output->state (full_state));
1172 node->add_child_nocopy (_speakers->get_state());
1173 node->add_child_nocopy (_tempo_map->get_state());
1174 node->add_child_nocopy (get_control_protocol_state());
1177 node->add_child_copy (*_extra_xml);
1184 Session::get_control_protocol_state ()
1186 ControlProtocolManager& cpm (ControlProtocolManager::instance());
1187 return cpm.get_state();
1191 Session::set_state (const XMLNode& node, int version)
1195 const XMLProperty* prop;
1198 _state_of_the_state = StateOfTheState (_state_of_the_state|CannotSave);
1200 if (node.name() != X_("Session")) {
1201 fatal << _("programming error: Session: incorrect XML node sent to set_state()") << endmsg;
1205 if ((prop = node.property ("name")) != 0) {
1206 _name = prop->value ();
1209 if ((prop = node.property (X_("sample-rate"))) != 0) {
1211 _nominal_frame_rate = atoi (prop->value());
1213 if (_nominal_frame_rate != _current_frame_rate) {
1214 boost::optional<int> r = AskAboutSampleRateMismatch (_nominal_frame_rate, _current_frame_rate);
1215 if (r.get_value_or (0)) {
1221 setup_raid_path(_session_dir->root_path());
1223 if ((prop = node.property (X_("id-counter"))) != 0) {
1225 sscanf (prop->value().c_str(), "%" PRIu64, &x);
1226 ID::init_counter (x);
1228 /* old sessions used a timebased counter, so fake
1229 the startup ID counter based on a standard
1234 ID::init_counter (now);
1237 if ((prop = node.property (X_("event-counter"))) != 0) {
1238 Evoral::init_event_id_counter (atoi (prop->value()));
1242 if ((child = find_named_node (node, "MIDIPorts")) != 0) {
1243 _midi_ports->set_midi_port_states (child->children());
1246 IO::disable_connecting ();
1248 Stateful::save_extra_xml (node);
1250 if (((child = find_named_node (node, "Options")) != 0)) { /* old style */
1251 load_options (*child);
1252 } else if ((child = find_named_node (node, "Config")) != 0) { /* new style */
1253 load_options (*child);
1255 error << _("Session: XML state has no options section") << endmsg;
1258 if (version >= 3000) {
1259 if ((child = find_named_node (node, "Metadata")) == 0) {
1260 warning << _("Session: XML state has no metadata section") << endmsg;
1261 } else if ( ARDOUR::SessionMetadata::Metadata()->set_state (*child, version) ) {
1266 if ((child = find_named_node (node, X_("Speakers"))) != 0) {
1267 _speakers->set_state (*child, version);
1270 if ((child = find_named_node (node, "Sources")) == 0) {
1271 error << _("Session: XML state has no sources section") << endmsg;
1273 } else if (load_sources (*child)) {
1277 if ((child = find_named_node (node, "TempoMap")) == 0) {
1278 error << _("Session: XML state has no Tempo Map section") << endmsg;
1280 } else if (_tempo_map->set_state (*child, version)) {
1284 if ((child = find_named_node (node, "Locations")) == 0) {
1285 error << _("Session: XML state has no locations section") << endmsg;
1287 } else if (_locations->set_state (*child, version)) {
1291 locations_changed ();
1293 if (_session_range_location) {
1294 AudioFileSource::set_header_position_offset (_session_range_location->start());
1297 if ((child = find_named_node (node, "Regions")) == 0) {
1298 error << _("Session: XML state has no Regions section") << endmsg;
1300 } else if (load_regions (*child)) {
1304 if ((child = find_named_node (node, "Playlists")) == 0) {
1305 error << _("Session: XML state has no playlists section") << endmsg;
1307 } else if (playlists->load (*this, *child)) {
1311 if ((child = find_named_node (node, "UnusedPlaylists")) == 0) {
1313 } else if (playlists->load_unused (*this, *child)) {
1317 if ((child = find_named_node (node, "CompoundAssociations")) != 0) {
1318 if (load_compounds (*child)) {
1323 if (version >= 3000) {
1324 if ((child = find_named_node (node, "Bundles")) == 0) {
1325 warning << _("Session: XML state has no bundles section") << endmsg;
1328 /* We can't load Bundles yet as they need to be able
1329 to convert from port names to Port objects, which can't happen until
1331 _bundle_xml_node = new XMLNode (*child);
1335 if (version < 3000) {
1336 if ((child = find_named_node (node, X_("DiskStreams"))) == 0) {
1337 error << _("Session: XML state has no diskstreams section") << endmsg;
1339 } else if (load_diskstreams_2X (*child, version)) {
1344 if ((child = find_named_node (node, "Routes")) == 0) {
1345 error << _("Session: XML state has no routes section") << endmsg;
1347 } else if (load_routes (*child, version)) {
1351 /* our diskstreams list is no longer needed as they are now all owned by their Route */
1352 _diskstreams_2X.clear ();
1354 if (version >= 3000) {
1356 if ((child = find_named_node (node, "RouteGroups")) == 0) {
1357 error << _("Session: XML state has no route groups section") << endmsg;
1359 } else if (load_route_groups (*child, version)) {
1363 } else if (version < 3000) {
1365 if ((child = find_named_node (node, "EditGroups")) == 0) {
1366 error << _("Session: XML state has no edit groups section") << endmsg;
1368 } else if (load_route_groups (*child, version)) {
1372 if ((child = find_named_node (node, "MixGroups")) == 0) {
1373 error << _("Session: XML state has no mix groups section") << endmsg;
1375 } else if (load_route_groups (*child, version)) {
1380 if ((child = find_named_node (node, "Click")) == 0) {
1381 warning << _("Session: XML state has no click section") << endmsg;
1382 } else if (_click_io) {
1383 setup_click_state (&node);
1386 if ((child = find_named_node (node, ControlProtocolManager::state_node_name)) != 0) {
1387 ControlProtocolManager::instance().set_state (*child, version);
1390 update_route_record_state ();
1392 /* here beginneth the second phase ... */
1394 StateReady (); /* EMIT SIGNAL */
1407 Session::load_routes (const XMLNode& node, int version)
1410 XMLNodeConstIterator niter;
1411 RouteList new_routes;
1413 nlist = node.children();
1417 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1419 boost::shared_ptr<Route> route;
1420 if (version < 3000) {
1421 route = XMLRouteFactory_2X (**niter, version);
1423 route = XMLRouteFactory (**niter, version);
1427 error << _("Session: cannot create Route from XML description.") << endmsg;
1431 BootMessage (string_compose (_("Loaded track/bus %1"), route->name()));
1433 new_routes.push_back (route);
1436 BootMessage (_("Tracks/busses loaded; Adding to Session"));
1438 add_routes (new_routes, false, false, false);
1440 BootMessage (_("Finished adding tracks/busses"));
1445 boost::shared_ptr<Route>
1446 Session::XMLRouteFactory (const XMLNode& node, int version)
1448 boost::shared_ptr<Route> ret;
1450 if (node.name() != "Route") {
1454 XMLNode* ds_child = find_named_node (node, X_("Diskstream"));
1456 DataType type = DataType::AUDIO;
1457 const XMLProperty* prop = node.property("default-type");
1460 type = DataType (prop->value());
1463 assert (type != DataType::NIL);
1467 boost::shared_ptr<Track> track;
1469 if (type == DataType::AUDIO) {
1470 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1472 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1475 if (track->init()) {
1479 if (track->set_state (node, version)) {
1483 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1484 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1489 enum Route::Flag flags = Route::Flag(0);
1490 const XMLProperty* prop = node.property("flags");
1492 flags = Route::Flag (string_2_enum (prop->value(), flags));
1495 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1497 if (r->init () == 0 && r->set_state (node, version) == 0) {
1498 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1499 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1508 boost::shared_ptr<Route>
1509 Session::XMLRouteFactory_2X (const XMLNode& node, int version)
1511 boost::shared_ptr<Route> ret;
1513 if (node.name() != "Route") {
1517 XMLProperty const * ds_prop = node.property (X_("diskstream-id"));
1519 ds_prop = node.property (X_("diskstream"));
1522 DataType type = DataType::AUDIO;
1523 const XMLProperty* prop = node.property("default-type");
1526 type = DataType (prop->value());
1529 assert (type != DataType::NIL);
1533 list<boost::shared_ptr<Diskstream> >::iterator i = _diskstreams_2X.begin ();
1534 while (i != _diskstreams_2X.end() && (*i)->id() != ds_prop->value()) {
1538 if (i == _diskstreams_2X.end()) {
1539 error << _("Could not find diskstream for route") << endmsg;
1540 return boost::shared_ptr<Route> ();
1543 boost::shared_ptr<Track> track;
1545 if (type == DataType::AUDIO) {
1546 track.reset (new AudioTrack (*this, X_("toBeResetFroXML")));
1548 track.reset (new MidiTrack (*this, X_("toBeResetFroXML")));
1551 if (track->init()) {
1555 if (track->set_state (node, version)) {
1559 track->set_diskstream (*i);
1561 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1562 // boost_debug_shared_ptr_mark_interesting (track.get(), "Track");
1567 enum Route::Flag flags = Route::Flag(0);
1568 const XMLProperty* prop = node.property("flags");
1570 flags = Route::Flag (string_2_enum (prop->value(), flags));
1573 boost::shared_ptr<Route> r (new Route (*this, X_("toBeResetFroXML"), flags));
1575 if (r->init () == 0 && r->set_state (node, version) == 0) {
1576 #ifdef BOOST_SP_ENABLE_DEBUG_HOOKS
1577 // boost_debug_shared_ptr_mark_interesting (r.get(), "Route");
1587 Session::load_regions (const XMLNode& node)
1590 XMLNodeConstIterator niter;
1591 boost::shared_ptr<Region> region;
1593 nlist = node.children();
1597 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1598 if ((region = XMLRegionFactory (**niter, false)) == 0) {
1599 error << _("Session: cannot create Region from XML description.");
1600 const XMLProperty *name = (**niter).property("name");
1603 error << " " << string_compose (_("Can not load state for region '%1'"), name->value());
1614 Session::load_compounds (const XMLNode& node)
1616 XMLNodeList calist = node.children();
1617 XMLNodeConstIterator caiter;
1618 XMLProperty *caprop;
1620 for (caiter = calist.begin(); caiter != calist.end(); ++caiter) {
1621 XMLNode* ca = *caiter;
1625 if ((caprop = ca->property (X_("original"))) == 0) {
1628 orig_id = caprop->value();
1630 if ((caprop = ca->property (X_("copy"))) == 0) {
1633 copy_id = caprop->value();
1635 boost::shared_ptr<Region> orig = RegionFactory::region_by_id (orig_id);
1636 boost::shared_ptr<Region> copy = RegionFactory::region_by_id (copy_id);
1638 if (!orig || !copy) {
1639 warning << string_compose (_("Regions in compound description not found (ID's %1 and %2): ignored"),
1645 RegionFactory::add_compound_association (orig, copy);
1652 Session::load_nested_sources (const XMLNode& node)
1655 XMLNodeConstIterator niter;
1657 nlist = node.children();
1659 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1660 if ((*niter)->name() == "Source") {
1662 /* it may already exist, so don't recreate it unnecessarily
1665 XMLProperty* prop = (*niter)->property (X_("id"));
1667 error << _("Nested source has no ID info in session file! (ignored)") << endmsg;
1671 ID source_id (prop->value());
1673 if (!source_by_id (source_id)) {
1676 SourceFactory::create (*this, **niter, true);
1678 catch (failed_constructor& err) {
1679 error << string_compose (_("Cannot reconstruct nested source for region %1"), name()) << endmsg;
1686 boost::shared_ptr<Region>
1687 Session::XMLRegionFactory (const XMLNode& node, bool full)
1689 const XMLProperty* type = node.property("type");
1693 const XMLNodeList& nlist = node.children();
1695 for (XMLNodeConstIterator niter = nlist.begin(); niter != nlist.end(); ++niter) {
1696 XMLNode *child = (*niter);
1697 if (child->name() == "NestedSource") {
1698 load_nested_sources (*child);
1702 if (!type || type->value() == "audio") {
1703 return boost::shared_ptr<Region>(XMLAudioRegionFactory (node, full));
1704 } else if (type->value() == "midi") {
1705 return boost::shared_ptr<Region>(XMLMidiRegionFactory (node, full));
1708 } catch (failed_constructor& err) {
1709 return boost::shared_ptr<Region> ();
1712 return boost::shared_ptr<Region> ();
1715 boost::shared_ptr<AudioRegion>
1716 Session::XMLAudioRegionFactory (const XMLNode& node, bool /*full*/)
1718 const XMLProperty* prop;
1719 boost::shared_ptr<Source> source;
1720 boost::shared_ptr<AudioSource> as;
1722 SourceList master_sources;
1723 uint32_t nchans = 1;
1726 if (node.name() != X_("Region")) {
1727 return boost::shared_ptr<AudioRegion>();
1730 if ((prop = node.property (X_("channels"))) != 0) {
1731 nchans = atoi (prop->value().c_str());
1734 if ((prop = node.property ("name")) == 0) {
1735 cerr << "no name for this region\n";
1739 if ((prop = node.property (X_("source-0"))) == 0) {
1740 if ((prop = node.property ("source")) == 0) {
1741 error << _("Session: XMLNode describing a AudioRegion is incomplete (no source)") << endmsg;
1742 return boost::shared_ptr<AudioRegion>();
1746 PBD::ID s_id (prop->value());
1748 if ((source = source_by_id (s_id)) == 0) {
1749 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), s_id) << endmsg;
1750 return boost::shared_ptr<AudioRegion>();
1753 as = boost::dynamic_pointer_cast<AudioSource>(source);
1755 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), s_id) << endmsg;
1756 return boost::shared_ptr<AudioRegion>();
1759 sources.push_back (as);
1761 /* pickup other channels */
1763 for (uint32_t n=1; n < nchans; ++n) {
1764 snprintf (buf, sizeof(buf), X_("source-%d"), n);
1765 if ((prop = node.property (buf)) != 0) {
1767 PBD::ID id2 (prop->value());
1769 if ((source = source_by_id (id2)) == 0) {
1770 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1771 return boost::shared_ptr<AudioRegion>();
1774 as = boost::dynamic_pointer_cast<AudioSource>(source);
1776 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1777 return boost::shared_ptr<AudioRegion>();
1779 sources.push_back (as);
1783 for (uint32_t n = 0; n < nchans; ++n) {
1784 snprintf (buf, sizeof(buf), X_("master-source-%d"), n);
1785 if ((prop = node.property (buf)) != 0) {
1787 PBD::ID id2 (prop->value());
1789 if ((source = source_by_id (id2)) == 0) {
1790 error << string_compose(_("Session: XMLNode describing a AudioRegion references an unknown source id =%1"), id2) << endmsg;
1791 return boost::shared_ptr<AudioRegion>();
1794 as = boost::dynamic_pointer_cast<AudioSource>(source);
1796 error << string_compose(_("Session: XMLNode describing a AudioRegion references a non-audio source id =%1"), id2) << endmsg;
1797 return boost::shared_ptr<AudioRegion>();
1799 master_sources.push_back (as);
1804 boost::shared_ptr<AudioRegion> region (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (sources, node)));
1806 /* a final detail: this is the one and only place that we know how long missing files are */
1808 if (region->whole_file()) {
1809 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1810 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1812 sfp->set_length (region->length());
1817 if (!master_sources.empty()) {
1818 if (master_sources.size() != nchans) {
1819 error << _("Session: XMLNode describing an AudioRegion is missing some master sources; ignored") << endmsg;
1821 region->set_master_sources (master_sources);
1829 catch (failed_constructor& err) {
1830 return boost::shared_ptr<AudioRegion>();
1834 boost::shared_ptr<MidiRegion>
1835 Session::XMLMidiRegionFactory (const XMLNode& node, bool /*full*/)
1837 const XMLProperty* prop;
1838 boost::shared_ptr<Source> source;
1839 boost::shared_ptr<MidiSource> ms;
1842 if (node.name() != X_("Region")) {
1843 return boost::shared_ptr<MidiRegion>();
1846 if ((prop = node.property ("name")) == 0) {
1847 cerr << "no name for this region\n";
1851 if ((prop = node.property (X_("source-0"))) == 0) {
1852 if ((prop = node.property ("source")) == 0) {
1853 error << _("Session: XMLNode describing a MidiRegion is incomplete (no source)") << endmsg;
1854 return boost::shared_ptr<MidiRegion>();
1858 PBD::ID s_id (prop->value());
1860 if ((source = source_by_id (s_id)) == 0) {
1861 error << string_compose(_("Session: XMLNode describing a MidiRegion references an unknown source id =%1"), s_id) << endmsg;
1862 return boost::shared_ptr<MidiRegion>();
1865 ms = boost::dynamic_pointer_cast<MidiSource>(source);
1867 error << string_compose(_("Session: XMLNode describing a MidiRegion references a non-midi source id =%1"), s_id) << endmsg;
1868 return boost::shared_ptr<MidiRegion>();
1871 sources.push_back (ms);
1874 boost::shared_ptr<MidiRegion> region (boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (sources, node)));
1875 /* a final detail: this is the one and only place that we know how long missing files are */
1877 if (region->whole_file()) {
1878 for (SourceList::iterator sx = sources.begin(); sx != sources.end(); ++sx) {
1879 boost::shared_ptr<SilentFileSource> sfp = boost::dynamic_pointer_cast<SilentFileSource> (*sx);
1881 sfp->set_length (region->length());
1889 catch (failed_constructor& err) {
1890 return boost::shared_ptr<MidiRegion>();
1895 Session::get_sources_as_xml ()
1898 XMLNode* node = new XMLNode (X_("Sources"));
1899 Glib::Threads::Mutex::Lock lm (source_lock);
1901 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
1902 node->add_child_nocopy (i->second->get_state());
1909 Session::reset_write_sources (bool mark_write_complete, bool force)
1911 boost::shared_ptr<RouteList> rl = routes.reader();
1912 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1913 boost::shared_ptr<Track> tr = boost::dynamic_pointer_cast<Track> (*i);
1916 // block state saving
1917 _state_of_the_state = StateOfTheState (_state_of_the_state|InCleanup);
1918 tr->reset_write_sources(mark_write_complete, force);
1919 _state_of_the_state = StateOfTheState (_state_of_the_state & ~InCleanup);
1925 Session::load_sources (const XMLNode& node)
1928 XMLNodeConstIterator niter;
1929 boost::shared_ptr<Source> source; /* don't need this but it stops some
1930 * versions of gcc complaining about
1931 * discarded return values.
1934 nlist = node.children();
1938 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
1941 if ((source = XMLSourceFactory (**niter)) == 0) {
1942 error << _("Session: cannot create Source from XML description.") << endmsg;
1945 } catch (MissingSource& err) {
1949 if (err.type == DataType::MIDI && Glib::path_is_absolute (err.path)) {
1950 error << string_compose (_("A external MIDI file is missing. %1 cannot currently recover from missing external MIDI files"),
1951 PROGRAM_NAME) << endmsg;
1955 if (!no_questions_about_missing_files) {
1956 user_choice = MissingFile (this, err.path, err.type).get_value_or (-1);
1961 switch (user_choice) {
1963 /* user added a new search location, so try again */
1968 /* user asked to quit the entire session load
1973 no_questions_about_missing_files = true;
1977 no_questions_about_missing_files = true;
1984 case DataType::AUDIO:
1985 source = SourceFactory::createSilent (*this, **niter, max_framecnt, _current_frame_rate);
1988 case DataType::MIDI:
1989 /* The MIDI file is actually missing so
1990 * just create a new one in the same
1991 * location. Do not announce its
1995 if (!Glib::path_is_absolute (err.path)) {
1996 fullpath = Glib::build_filename (source_search_path (DataType::MIDI).front(), err.path);
1998 /* this should be an unrecoverable error: we would be creating a MIDI file outside
2003 /* Note that we do not announce the source just yet - we need to reset its ID before we do that */
2004 source = SourceFactory::createWritable (DataType::MIDI, *this, fullpath, false, _current_frame_rate, false, false);
2005 /* reset ID to match the missing one */
2006 source->set_id (**niter);
2007 /* Now we can announce it */
2008 SourceFactory::SourceCreated (source);
2019 boost::shared_ptr<Source>
2020 Session::XMLSourceFactory (const XMLNode& node)
2022 if (node.name() != "Source") {
2023 return boost::shared_ptr<Source>();
2027 /* note: do peak building in another thread when loading session state */
2028 return SourceFactory::create (*this, node, true);
2031 catch (failed_constructor& err) {
2032 error << string_compose (_("Found a sound file that cannot be used by %1. Talk to the programmers."), PROGRAM_NAME) << endmsg;
2033 return boost::shared_ptr<Source>();
2038 Session::save_template (string template_name)
2040 if ((_state_of_the_state & CannotSave) || template_name.empty ()) {
2044 bool absolute_path = Glib::path_is_absolute (template_name);
2046 /* directory to put the template in */
2047 std::string template_dir_path;
2049 if (!absolute_path) {
2050 std::string user_template_dir(user_template_directory());
2052 if (g_mkdir_with_parents (user_template_dir.c_str(), 0755) != 0) {
2053 error << string_compose(_("Could not create templates directory \"%1\" (%2)"),
2054 user_template_dir, g_strerror (errno)) << endmsg;
2058 template_dir_path = Glib::build_filename (user_template_dir, template_name);
2060 template_dir_path = template_name;
2063 if (!ARDOUR::Profile->get_trx()) {
2064 if (Glib::file_test (template_dir_path, Glib::FILE_TEST_EXISTS)) {
2065 warning << string_compose(_("Template \"%1\" already exists - new version not created"),
2066 template_dir_path) << endmsg;
2070 if (g_mkdir_with_parents (template_dir_path.c_str(), 0755) != 0) {
2071 error << string_compose(_("Could not create directory for Session template\"%1\" (%2)"),
2072 template_dir_path, g_strerror (errno)) << endmsg;
2078 std::string template_file_path;
2080 if (ARDOUR::Profile->get_trx()) {
2081 template_file_path = template_name;
2083 if (absolute_path) {
2084 template_file_path = Glib::build_filename (template_dir_path, Glib::path_get_basename (template_dir_path) + template_suffix);
2086 template_file_path = Glib::build_filename (template_dir_path, template_name + template_suffix);
2090 SessionSaveUnderway (); /* EMIT SIGNAL */
2094 tree.set_root (&get_template());
2095 if (!tree.write (template_file_path)) {
2096 error << _("template not saved") << endmsg;
2100 if (!ARDOUR::Profile->get_trx()) {
2101 /* copy plugin state directory */
2103 std::string template_plugin_state_path (Glib::build_filename (template_dir_path, X_("plugins")));
2105 if (g_mkdir_with_parents (template_plugin_state_path.c_str(), 0755) != 0) {
2106 error << string_compose(_("Could not create directory for Session template plugin state\"%1\" (%2)"),
2107 template_plugin_state_path, g_strerror (errno)) << endmsg;
2110 copy_files (plugins_dir(), template_plugin_state_path);
2113 store_recent_templates (template_file_path);
2119 Session::refresh_disk_space ()
2121 #if __APPLE__ || (HAVE_SYS_VFS_H && HAVE_SYS_STATVFS_H)
2123 Glib::Threads::Mutex::Lock lm (space_lock);
2125 /* get freespace on every FS that is part of the session path */
2127 _total_free_4k_blocks = 0;
2128 _total_free_4k_blocks_uncertain = false;
2130 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2132 struct statfs statfsbuf;
2133 statfs (i->path.c_str(), &statfsbuf);
2135 double const scale = statfsbuf.f_bsize / 4096.0;
2137 /* See if this filesystem is read-only */
2138 struct statvfs statvfsbuf;
2139 statvfs (i->path.c_str(), &statvfsbuf);
2141 /* f_bavail can be 0 if it is undefined for whatever
2142 filesystem we are looking at; Samba shares mounted
2143 via GVFS are an example of this.
2145 if (statfsbuf.f_bavail == 0) {
2146 /* block count unknown */
2148 i->blocks_unknown = true;
2149 } else if (statvfsbuf.f_flag & ST_RDONLY) {
2150 /* read-only filesystem */
2152 i->blocks_unknown = false;
2154 /* read/write filesystem with known space */
2155 i->blocks = (uint32_t) floor (statfsbuf.f_bavail * scale);
2156 i->blocks_unknown = false;
2159 _total_free_4k_blocks += i->blocks;
2160 if (i->blocks_unknown) {
2161 _total_free_4k_blocks_uncertain = true;
2164 #elif defined PLATFORM_WINDOWS
2165 vector<string> scanned_volumes;
2166 vector<string>::iterator j;
2167 vector<space_and_path>::iterator i;
2168 DWORD nSectorsPerCluster, nBytesPerSector,
2169 nFreeClusters, nTotalClusters;
2173 _total_free_4k_blocks = 0;
2175 for (i = session_dirs.begin(); i != session_dirs.end(); i++) {
2176 strncpy (disk_drive, (*i).path.c_str(), 3);
2180 volume_found = false;
2181 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2183 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2184 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2185 i->blocks = (uint32_t)(nFreeBytes / 4096);
2187 for (j = scanned_volumes.begin(); j != scanned_volumes.end(); j++) {
2188 if (0 == j->compare(disk_drive)) {
2189 volume_found = true;
2194 if (!volume_found) {
2195 scanned_volumes.push_back(disk_drive);
2196 _total_free_4k_blocks += i->blocks;
2201 if (0 == _total_free_4k_blocks) {
2202 strncpy (disk_drive, path().c_str(), 3);
2205 if (0 != (GetDiskFreeSpace(disk_drive, &nSectorsPerCluster, &nBytesPerSector, &nFreeClusters, &nTotalClusters)))
2207 int64_t nBytesPerCluster = nBytesPerSector * nSectorsPerCluster;
2208 int64_t nFreeBytes = nBytesPerCluster * (int64_t)nFreeClusters;
2209 _total_free_4k_blocks = (uint32_t)(nFreeBytes / 4096);
2216 Session::get_best_session_directory_for_new_audio ()
2218 vector<space_and_path>::iterator i;
2219 string result = _session_dir->root_path();
2221 /* handle common case without system calls */
2223 if (session_dirs.size() == 1) {
2227 /* OK, here's the algorithm we're following here:
2229 We want to select which directory to use for
2230 the next file source to be created. Ideally,
2231 we'd like to use a round-robin process so as to
2232 get maximum performance benefits from splitting
2233 the files across multiple disks.
2235 However, in situations without much diskspace, an
2236 RR approach may end up filling up a filesystem
2237 with new files while others still have space.
2238 Its therefore important to pay some attention to
2239 the freespace in the filesystem holding each
2240 directory as well. However, if we did that by
2241 itself, we'd keep creating new files in the file
2242 system with the most space until it was as full
2243 as all others, thus negating any performance
2244 benefits of this RAID-1 like approach.
2246 So, we use a user-configurable space threshold. If
2247 there are at least 2 filesystems with more than this
2248 much space available, we use RR selection between them.
2249 If not, then we pick the filesystem with the most space.
2251 This gets a good balance between the two
2255 refresh_disk_space ();
2257 int free_enough = 0;
2259 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2260 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2265 if (free_enough >= 2) {
2266 /* use RR selection process, ensuring that the one
2270 i = last_rr_session_dir;
2273 if (++i == session_dirs.end()) {
2274 i = session_dirs.begin();
2277 if ((*i).blocks * 4096 >= Config->get_disk_choice_space_threshold()) {
2278 SessionDirectory sdir(i->path);
2279 if (sdir.create ()) {
2281 last_rr_session_dir = i;
2286 } while (i != last_rr_session_dir);
2290 /* pick FS with the most freespace (and that
2291 seems to actually work ...)
2294 vector<space_and_path> sorted;
2295 space_and_path_ascending_cmp cmp;
2297 sorted = session_dirs;
2298 sort (sorted.begin(), sorted.end(), cmp);
2300 for (i = sorted.begin(); i != sorted.end(); ++i) {
2301 SessionDirectory sdir(i->path);
2302 if (sdir.create ()) {
2304 last_rr_session_dir = i;
2314 Session::automation_dir () const
2316 return Glib::build_filename (_path, "automation");
2320 Session::analysis_dir () const
2322 return Glib::build_filename (_path, "analysis");
2326 Session::plugins_dir () const
2328 return Glib::build_filename (_path, "plugins");
2332 Session::externals_dir () const
2334 return Glib::build_filename (_path, "externals");
2338 Session::load_bundles (XMLNode const & node)
2340 XMLNodeList nlist = node.children();
2341 XMLNodeConstIterator niter;
2345 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2346 if ((*niter)->name() == "InputBundle") {
2347 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, true)));
2348 } else if ((*niter)->name() == "OutputBundle") {
2349 add_bundle (boost::shared_ptr<UserBundle> (new UserBundle (**niter, false)));
2351 error << string_compose(_("Unknown node \"%1\" found in Bundles list from session file"), (*niter)->name()) << endmsg;
2360 Session::load_route_groups (const XMLNode& node, int version)
2362 XMLNodeList nlist = node.children();
2363 XMLNodeConstIterator niter;
2367 if (version >= 3000) {
2369 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2370 if ((*niter)->name() == "RouteGroup") {
2371 RouteGroup* rg = new RouteGroup (*this, "");
2372 add_route_group (rg);
2373 rg->set_state (**niter, version);
2377 } else if (version < 3000) {
2379 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2380 if ((*niter)->name() == "EditGroup" || (*niter)->name() == "MixGroup") {
2381 RouteGroup* rg = new RouteGroup (*this, "");
2382 add_route_group (rg);
2383 rg->set_state (**niter, version);
2392 state_file_filter (const string &str, void* /*arg*/)
2394 return (str.length() > strlen(statefile_suffix) &&
2395 str.find (statefile_suffix) == (str.length() - strlen (statefile_suffix)));
2399 remove_end(string state)
2401 string statename(state);
2403 string::size_type start,end;
2404 if ((start = statename.find_last_of (G_DIR_SEPARATOR)) != string::npos) {
2405 statename = statename.substr (start+1);
2408 if ((end = statename.rfind(statefile_suffix)) == string::npos) {
2409 end = statename.length();
2412 return string(statename.substr (0, end));
2416 Session::possible_states (string path)
2418 vector<string> states;
2419 find_files_matching_filter (states, path, state_file_filter, 0, false, false);
2421 transform(states.begin(), states.end(), states.begin(), remove_end);
2423 sort (states.begin(), states.end());
2429 Session::possible_states () const
2431 return possible_states(_path);
2435 Session::add_route_group (RouteGroup* g)
2437 _route_groups.push_back (g);
2438 route_group_added (g); /* EMIT SIGNAL */
2440 g->RouteAdded.connect_same_thread (*this, boost::bind (&Session::route_added_to_route_group, this, _1, _2));
2441 g->RouteRemoved.connect_same_thread (*this, boost::bind (&Session::route_removed_from_route_group, this, _1, _2));
2442 g->PropertyChanged.connect_same_thread (*this, boost::bind (&Session::route_group_property_changed, this, g));
2448 Session::remove_route_group (RouteGroup& rg)
2450 list<RouteGroup*>::iterator i;
2452 if ((i = find (_route_groups.begin(), _route_groups.end(), &rg)) != _route_groups.end()) {
2453 _route_groups.erase (i);
2456 route_group_removed (); /* EMIT SIGNAL */
2460 /** Set a new order for our route groups, without adding or removing any.
2461 * @param groups Route group list in the new order.
2464 Session::reorder_route_groups (list<RouteGroup*> groups)
2466 _route_groups = groups;
2468 route_groups_reordered (); /* EMIT SIGNAL */
2474 Session::route_group_by_name (string name)
2476 list<RouteGroup *>::iterator i;
2478 for (i = _route_groups.begin(); i != _route_groups.end(); ++i) {
2479 if ((*i)->name() == name) {
2487 Session::all_route_group() const
2489 return *_all_route_group;
2493 Session::add_commands (vector<Command*> const & cmds)
2495 for (vector<Command*>::const_iterator i = cmds.begin(); i != cmds.end(); ++i) {
2501 Session::begin_reversible_command (const string& name)
2503 begin_reversible_command (g_quark_from_string (name.c_str ()));
2506 /** Begin a reversible command using a GQuark to identify it.
2507 * begin_reversible_command() and commit_reversible_command() calls may be nested,
2508 * but there must be as many begin...()s as there are commit...()s.
2511 Session::begin_reversible_command (GQuark q)
2513 /* If nested begin/commit pairs are used, we create just one UndoTransaction
2514 to hold all the commands that are committed. This keeps the order of
2515 commands correct in the history.
2518 if (_current_trans == 0) {
2519 /* start a new transaction */
2520 assert (_current_trans_quarks.empty ());
2521 _current_trans = new UndoTransaction();
2522 _current_trans->set_name (g_quark_to_string (q));
2525 _current_trans_quarks.push_front (q);
2529 Session::abort_reversible_command ()
2531 if (_current_trans != 0) {
2532 _current_trans->clear();
2533 delete _current_trans;
2535 _current_trans_quarks.clear();
2540 Session::commit_reversible_command (Command *cmd)
2542 assert (_current_trans);
2543 assert (!_current_trans_quarks.empty ());
2548 _current_trans->add_command (cmd);
2551 _current_trans_quarks.pop_front ();
2553 if (!_current_trans_quarks.empty ()) {
2554 /* the transaction we're committing is not the top-level one */
2558 if (_current_trans->empty()) {
2559 /* no commands were added to the transaction, so just get rid of it */
2560 delete _current_trans;
2565 gettimeofday (&now, 0);
2566 _current_trans->set_timestamp (now);
2568 _history.add (_current_trans);
2573 accept_all_audio_files (const string& path, void* /*arg*/)
2575 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2579 if (!AudioFileSource::safe_audio_file_extension (path)) {
2587 accept_all_midi_files (const string& path, void* /*arg*/)
2589 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2593 return ((path.length() > 4 && path.find (".mid") != (path.length() - 4)) ||
2594 (path.length() > 4 && path.find (".smf") != (path.length() - 4)) ||
2595 (path.length() > 5 && path.find (".midi") != (path.length() - 5)));
2599 accept_all_state_files (const string& path, void* /*arg*/)
2601 if (!Glib::file_test (path, Glib::FILE_TEST_IS_REGULAR)) {
2605 std::string const statefile_ext (statefile_suffix);
2606 if (path.length() >= statefile_ext.length()) {
2607 return (0 == path.compare (path.length() - statefile_ext.length(), statefile_ext.length(), statefile_ext));
2614 Session::find_all_sources (string path, set<string>& result)
2619 if (!tree.read (path)) {
2623 if ((node = find_named_node (*tree.root(), "Sources")) == 0) {
2628 XMLNodeConstIterator niter;
2630 nlist = node->children();
2634 for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
2638 if ((prop = (*niter)->property (X_("type"))) == 0) {
2642 DataType type (prop->value());
2644 if ((prop = (*niter)->property (X_("name"))) == 0) {
2648 if (Glib::path_is_absolute (prop->value())) {
2649 /* external file, ignore */
2657 if (FileSource::find (*this, type, prop->value(), true, is_new, chan, found_path)) {
2658 result.insert (found_path);
2666 Session::find_all_sources_across_snapshots (set<string>& result, bool exclude_this_snapshot)
2668 vector<string> state_files;
2670 string this_snapshot_path;
2676 if (ripped[ripped.length()-1] == G_DIR_SEPARATOR) {
2677 ripped = ripped.substr (0, ripped.length() - 1);
2680 find_files_matching_filter (state_files, ripped, accept_all_state_files, (void *) 0, true, true);
2682 if (state_files.empty()) {
2687 this_snapshot_path = _path;
2688 this_snapshot_path += legalize_for_path (_current_snapshot_name);
2689 this_snapshot_path += statefile_suffix;
2691 for (vector<string>::iterator i = state_files.begin(); i != state_files.end(); ++i) {
2693 if (exclude_this_snapshot && *i == this_snapshot_path) {
2697 if (find_all_sources (*i, result) < 0) {
2705 struct RegionCounter {
2706 typedef std::map<PBD::ID,boost::shared_ptr<AudioSource> > AudioSourceList;
2707 AudioSourceList::iterator iter;
2708 boost::shared_ptr<Region> region;
2711 RegionCounter() : count (0) {}
2715 Session::ask_about_playlist_deletion (boost::shared_ptr<Playlist> p)
2717 boost::optional<int> r = AskAboutPlaylistDeletion (p);
2718 return r.get_value_or (1);
2722 Session::cleanup_regions ()
2724 bool removed = false;
2725 const RegionFactory::RegionMap& regions (RegionFactory::regions());
2727 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2729 uint32_t used = playlists->region_use_count (i->second);
2731 if (used == 0 && !i->second->automatic ()) {
2733 RegionFactory::map_remove (i->second);
2738 // re-check to remove parent references of compound regions
2739 for (RegionFactory::RegionMap::const_iterator i = regions.begin(); i != regions.end(); ++i) {
2740 if (!(i->second->whole_file() && i->second->max_source_level() > 0)) {
2743 assert(boost::dynamic_pointer_cast<PlaylistSource>(i->second->source (0)) != 0);
2744 if (0 == playlists->region_use_count (i->second)) {
2745 RegionFactory::map_remove (i->second);
2750 /* dump the history list */
2757 Session::cleanup_sources (CleanupReport& rep)
2759 // FIXME: needs adaptation to midi
2761 vector<boost::shared_ptr<Source> > dead_sources;
2764 vector<string> candidates;
2765 vector<string> unused;
2766 set<string> all_sources;
2775 _state_of_the_state = (StateOfTheState) (_state_of_the_state | InCleanup);
2777 /* consider deleting all unused playlists */
2779 if (playlists->maybe_delete_unused (boost::bind (Session::ask_about_playlist_deletion, _1))) {
2784 /* sync the "all regions" property of each playlist with its current state
2787 playlists->sync_all_regions_with_regions ();
2789 /* find all un-used sources */
2794 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2796 SourceMap::iterator tmp;
2801 /* do not bother with files that are zero size, otherwise we remove the current "nascent"
2805 if (!i->second->used() && (i->second->length(i->second->timeline_position() > 0))) {
2806 dead_sources.push_back (i->second);
2807 i->second->drop_references ();
2813 /* build a list of all the possible audio directories for the session */
2815 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2816 SessionDirectory sdir ((*i).path);
2817 asp += sdir.sound_path();
2819 audio_path += asp.to_string();
2822 /* build a list of all the possible midi directories for the session */
2824 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
2825 SessionDirectory sdir ((*i).path);
2826 msp += sdir.midi_path();
2828 midi_path += msp.to_string();
2830 find_files_matching_filter (candidates, audio_path, accept_all_audio_files, (void *) 0, true, true);
2831 find_files_matching_filter (candidates, midi_path, accept_all_midi_files, (void *) 0, true, true);
2833 /* find all sources, but don't use this snapshot because the
2834 state file on disk still references sources we may have already
2838 find_all_sources_across_snapshots (all_sources, true);
2840 /* add our current source list
2843 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ) {
2844 boost::shared_ptr<FileSource> fs;
2845 SourceMap::iterator tmp = i;
2848 if ((fs = boost::dynamic_pointer_cast<FileSource> (i->second)) != 0) {
2850 if (!fs->is_stub()) {
2852 if (playlists->source_use_count (fs) != 0) {
2853 all_sources.insert (fs->path());
2856 /* we might not remove this source from disk, because it may be used
2857 by other snapshots, but its not being used in this version
2858 so lets get rid of it now, along with any representative regions
2862 RegionFactory::remove_regions_using_source (i->second);
2865 // also remove source from all_sources
2867 for (set<string>::iterator j = all_sources.begin(); j != all_sources.end(); ++j) {
2868 spath = Glib::path_get_basename (*j);
2869 if ( spath == i->second->name () ) {
2870 all_sources.erase (j);
2881 for (vector<string>::iterator x = candidates.begin(); x != candidates.end(); ++x) {
2886 for (set<string>::iterator i = all_sources.begin(); i != all_sources.end(); ++i) {
2888 tmppath1 = canonical_path (spath);
2889 tmppath2 = canonical_path ((*i));
2891 if (tmppath1 == tmppath2) {
2898 unused.push_back (spath);
2902 /* now try to move all unused files into the "dead" directory(ies) */
2904 for (vector<string>::iterator x = unused.begin(); x != unused.end(); ++x) {
2905 struct stat statbuf;
2909 /* don't move the file across filesystems, just
2910 stick it in the `dead_dir_name' directory
2911 on whichever filesystem it was already on.
2914 if ((*x).find ("/sounds/") != string::npos) {
2916 /* old school, go up 1 level */
2918 newpath = Glib::path_get_dirname (*x); // "sounds"
2919 newpath = Glib::path_get_dirname (newpath); // "session-name"
2923 /* new school, go up 4 levels */
2925 newpath = Glib::path_get_dirname (*x); // "audiofiles" or "midifiles"
2926 newpath = Glib::path_get_dirname (newpath); // "session-name"
2927 newpath = Glib::path_get_dirname (newpath); // "interchange"
2928 newpath = Glib::path_get_dirname (newpath); // "session-dir"
2931 newpath = Glib::build_filename (newpath, dead_dir_name);
2933 if (g_mkdir_with_parents (newpath.c_str(), 0755) < 0) {
2934 error << string_compose(_("Session: cannot create dead file folder \"%1\" (%2)"), newpath, strerror (errno)) << endmsg;
2938 newpath = Glib::build_filename (newpath, Glib::path_get_basename ((*x)));
2940 if (Glib::file_test (newpath, Glib::FILE_TEST_EXISTS)) {
2942 /* the new path already exists, try versioning */
2944 char buf[PATH_MAX+1];
2948 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), version);
2951 while (Glib::file_test (newpath_v.c_str(), Glib::FILE_TEST_EXISTS) && version < 999) {
2952 snprintf (buf, sizeof (buf), "%s.%d", newpath.c_str(), ++version);
2956 if (version == 999) {
2957 error << string_compose (_("there are already 1000 files with names like %1; versioning discontinued"),
2961 newpath = newpath_v;
2966 /* it doesn't exist, or we can't read it or something */
2970 stat ((*x).c_str(), &statbuf);
2972 if (::rename ((*x).c_str(), newpath.c_str()) != 0) {
2973 error << string_compose (_("cannot rename unused file source from %1 to %2 (%3)"),
2974 (*x), newpath, strerror (errno))
2979 /* see if there an easy to find peakfile for this file, and remove it.
2982 string base = basename_nosuffix (*x);
2983 base += "%A"; /* this is what we add for the channel suffix of all native files,
2984 or for the first channel of embedded files. it will miss
2985 some peakfiles for other channels
2987 string peakpath = peak_path (base);
2989 if (Glib::file_test (peakpath.c_str(), Glib::FILE_TEST_EXISTS)) {
2990 if (::g_unlink (peakpath.c_str()) != 0) {
2991 error << string_compose (_("cannot remove peakfile %1 for %2 (%3)"),
2992 peakpath, _path, strerror (errno))
2994 /* try to back out */
2995 ::rename (newpath.c_str(), _path.c_str());
3000 rep.paths.push_back (*x);
3001 rep.space += statbuf.st_size;
3004 /* dump the history list */
3008 /* save state so we don't end up a session file
3009 referring to non-existent sources.
3016 _state_of_the_state = (StateOfTheState) (_state_of_the_state & ~InCleanup);
3022 Session::cleanup_trash_sources (CleanupReport& rep)
3024 // FIXME: needs adaptation for MIDI
3026 vector<space_and_path>::iterator i;
3032 for (i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3034 dead_dir = Glib::build_filename ((*i).path, dead_dir_name);
3036 clear_directory (dead_dir, &rep.space, &rep.paths);
3043 Session::set_dirty ()
3045 /* never mark session dirty during loading */
3047 if (_state_of_the_state & Loading) {
3051 bool was_dirty = dirty();
3053 _state_of_the_state = StateOfTheState (_state_of_the_state | Dirty);
3057 DirtyChanged(); /* EMIT SIGNAL */
3063 Session::set_clean ()
3065 bool was_dirty = dirty();
3067 _state_of_the_state = Clean;
3071 DirtyChanged(); /* EMIT SIGNAL */
3076 Session::set_deletion_in_progress ()
3078 _state_of_the_state = StateOfTheState (_state_of_the_state | Deletion);
3082 Session::clear_deletion_in_progress ()
3084 _state_of_the_state = StateOfTheState (_state_of_the_state & (~Deletion));
3088 Session::add_controllable (boost::shared_ptr<Controllable> c)
3090 /* this adds a controllable to the list managed by the Session.
3091 this is a subset of those managed by the Controllable class
3092 itself, and represents the only ones whose state will be saved
3093 as part of the session.
3096 Glib::Threads::Mutex::Lock lm (controllables_lock);
3097 controllables.insert (c);
3100 struct null_deleter { void operator()(void const *) const {} };
3103 Session::remove_controllable (Controllable* c)
3105 if (_state_of_the_state & Deletion) {
3109 Glib::Threads::Mutex::Lock lm (controllables_lock);
3111 Controllables::iterator x = controllables.find (boost::shared_ptr<Controllable>(c, null_deleter()));
3113 if (x != controllables.end()) {
3114 controllables.erase (x);
3118 boost::shared_ptr<Controllable>
3119 Session::controllable_by_id (const PBD::ID& id)
3121 Glib::Threads::Mutex::Lock lm (controllables_lock);
3123 for (Controllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
3124 if ((*i)->id() == id) {
3129 return boost::shared_ptr<Controllable>();
3132 boost::shared_ptr<Controllable>
3133 Session::controllable_by_descriptor (const ControllableDescriptor& desc)
3135 boost::shared_ptr<Controllable> c;
3136 boost::shared_ptr<Route> r;
3138 switch (desc.top_level_type()) {
3139 case ControllableDescriptor::NamedRoute:
3141 std::string str = desc.top_level_name();
3142 if (str == "Master" || str == "master") {
3144 } else if (str == "control" || str == "listen") {
3147 r = route_by_name (desc.top_level_name());
3152 case ControllableDescriptor::RemoteControlID:
3153 r = route_by_remote_id (desc.rid());
3161 switch (desc.subtype()) {
3162 case ControllableDescriptor::Gain:
3163 c = r->gain_control ();
3166 case ControllableDescriptor::Trim:
3167 c = r->trim()->gain_control ();
3170 case ControllableDescriptor::Solo:
3171 c = r->solo_control();
3174 case ControllableDescriptor::Mute:
3175 c = r->mute_control();
3178 case ControllableDescriptor::Recenable:
3180 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(r);
3183 c = t->rec_enable_control ();
3188 case ControllableDescriptor::PanDirection:
3190 c = r->pannable()->pan_azimuth_control;
3194 case ControllableDescriptor::PanWidth:
3196 c = r->pannable()->pan_width_control;
3200 case ControllableDescriptor::PanElevation:
3202 c = r->pannable()->pan_elevation_control;
3206 case ControllableDescriptor::Balance:
3207 /* XXX simple pan control */
3210 case ControllableDescriptor::PluginParameter:
3212 uint32_t plugin = desc.target (0);
3213 uint32_t parameter_index = desc.target (1);
3215 /* revert to zero based counting */
3221 if (parameter_index > 0) {
3225 boost::shared_ptr<Processor> p = r->nth_plugin (plugin);
3228 c = boost::dynamic_pointer_cast<ARDOUR::AutomationControl>(
3229 p->control(Evoral::Parameter(PluginAutomation, 0, parameter_index)));
3234 case ControllableDescriptor::SendGain:
3236 uint32_t send = desc.target (0);
3238 /* revert to zero-based counting */
3244 boost::shared_ptr<Processor> p = r->nth_send (send);
3247 boost::shared_ptr<Send> s = boost::dynamic_pointer_cast<Send>(p);
3248 boost::shared_ptr<Amp> a = s->amp();
3251 c = s->amp()->gain_control();
3258 /* relax and return a null pointer */
3266 Session::add_instant_xml (XMLNode& node, bool write_to_config)
3269 Stateful::add_instant_xml (node, _path);
3272 if (write_to_config) {
3273 Config->add_instant_xml (node);
3278 Session::instant_xml (const string& node_name)
3280 return Stateful::instant_xml (node_name, _path);
3284 Session::save_history (string snapshot_name)
3292 if (!Config->get_save_history() || Config->get_saved_history_depth() < 0 ||
3293 (_history.undo_depth() == 0 && _history.redo_depth() == 0)) {
3297 if (snapshot_name.empty()) {
3298 snapshot_name = _current_snapshot_name;
3301 const string history_filename = legalize_for_path (snapshot_name) + history_suffix;
3302 const string backup_filename = history_filename + backup_suffix;
3303 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), history_filename));
3304 const std::string backup_path(Glib::build_filename (_session_dir->root_path(), backup_filename));
3306 if (Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3307 if (::g_rename (xml_path.c_str(), backup_path.c_str()) != 0) {
3308 error << _("could not backup old history file, current history not saved") << endmsg;
3313 tree.set_root (&_history.get_state (Config->get_saved_history_depth()));
3315 if (!tree.write (xml_path))
3317 error << string_compose (_("history could not be saved to %1"), xml_path) << endmsg;
3319 if (g_remove (xml_path.c_str()) != 0) {
3320 error << string_compose(_("Could not remove history file at path \"%1\" (%2)"),
3321 xml_path, g_strerror (errno)) << endmsg;
3323 if (::g_rename (backup_path.c_str(), xml_path.c_str()) != 0) {
3324 error << string_compose (_("could not restore history file from backup %1 (%2)"),
3325 backup_path, g_strerror (errno)) << endmsg;
3335 Session::restore_history (string snapshot_name)
3339 if (snapshot_name.empty()) {
3340 snapshot_name = _current_snapshot_name;
3343 const std::string xml_filename = legalize_for_path (snapshot_name) + history_suffix;
3344 const std::string xml_path(Glib::build_filename (_session_dir->root_path(), xml_filename));
3346 info << "Loading history from " << xml_path << endmsg;
3348 if (!Glib::file_test (xml_path, Glib::FILE_TEST_EXISTS)) {
3349 info << string_compose (_("%1: no history file \"%2\" for this session."),
3350 _name, xml_path) << endmsg;
3354 if (!tree.read (xml_path)) {
3355 error << string_compose (_("Could not understand session history file \"%1\""),
3356 xml_path) << endmsg;
3363 for (XMLNodeConstIterator it = tree.root()->children().begin(); it != tree.root()->children().end(); it++) {
3366 UndoTransaction* ut = new UndoTransaction ();
3369 ut->set_name(t->property("name")->value());
3370 stringstream ss(t->property("tv-sec")->value());
3372 ss.str(t->property("tv-usec")->value());
3374 ut->set_timestamp(tv);
3376 for (XMLNodeConstIterator child_it = t->children().begin();
3377 child_it != t->children().end(); child_it++)
3379 XMLNode *n = *child_it;
3382 if (n->name() == "MementoCommand" ||
3383 n->name() == "MementoUndoCommand" ||
3384 n->name() == "MementoRedoCommand") {
3386 if ((c = memento_command_factory(n))) {
3390 } else if (n->name() == "NoteDiffCommand") {
3391 PBD::ID id (n->property("midi-source")->value());
3392 boost::shared_ptr<MidiSource> midi_source =
3393 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3395 ut->add_command (new MidiModel::NoteDiffCommand(midi_source->model(), *n));
3397 error << _("Failed to downcast MidiSource for NoteDiffCommand") << endmsg;
3400 } else if (n->name() == "SysExDiffCommand") {
3402 PBD::ID id (n->property("midi-source")->value());
3403 boost::shared_ptr<MidiSource> midi_source =
3404 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3406 ut->add_command (new MidiModel::SysExDiffCommand (midi_source->model(), *n));
3408 error << _("Failed to downcast MidiSource for SysExDiffCommand") << endmsg;
3411 } else if (n->name() == "PatchChangeDiffCommand") {
3413 PBD::ID id (n->property("midi-source")->value());
3414 boost::shared_ptr<MidiSource> midi_source =
3415 boost::dynamic_pointer_cast<MidiSource, Source>(source_by_id(id));
3417 ut->add_command (new MidiModel::PatchChangeDiffCommand (midi_source->model(), *n));
3419 error << _("Failed to downcast MidiSource for PatchChangeDiffCommand") << endmsg;
3422 } else if (n->name() == "StatefulDiffCommand") {
3423 if ((c = stateful_diff_command_factory (n))) {
3424 ut->add_command (c);
3427 error << string_compose(_("Couldn't figure out how to make a Command out of a %1 XMLNode."), n->name()) << endmsg;
3438 Session::config_changed (std::string p, bool ours)
3444 if (p == "seamless-loop") {
3446 } else if (p == "rf-speed") {
3448 } else if (p == "auto-loop") {
3450 } else if (p == "auto-input") {
3452 if (Config->get_monitoring_model() == HardwareMonitoring && transport_rolling()) {
3453 /* auto-input only makes a difference if we're rolling */
3454 set_track_monitor_input_status (!config.get_auto_input());
3457 } else if (p == "punch-in") {
3461 if ((location = _locations->auto_punch_location()) != 0) {
3463 if (config.get_punch_in ()) {
3464 replace_event (SessionEvent::PunchIn, location->start());
3466 remove_event (location->start(), SessionEvent::PunchIn);
3470 } else if (p == "punch-out") {
3474 if ((location = _locations->auto_punch_location()) != 0) {
3476 if (config.get_punch_out()) {
3477 replace_event (SessionEvent::PunchOut, location->end());
3479 clear_events (SessionEvent::PunchOut);
3483 } else if (p == "edit-mode") {
3485 Glib::Threads::Mutex::Lock lm (playlists->lock);
3487 for (SessionPlaylists::List::iterator i = playlists->playlists.begin(); i != playlists->playlists.end(); ++i) {
3488 (*i)->set_edit_mode (Config->get_edit_mode ());
3491 } else if (p == "use-video-sync") {
3493 waiting_for_sync_offset = config.get_use_video_sync();
3495 } else if (p == "mmc-control") {
3497 //poke_midi_thread ();
3499 } else if (p == "mmc-device-id" || p == "mmc-receive-id" || p == "mmc-receive-device-id") {
3501 _mmc->set_receive_device_id (Config->get_mmc_receive_device_id());
3503 } else if (p == "mmc-send-id" || p == "mmc-send-device-id") {
3505 _mmc->set_send_device_id (Config->get_mmc_send_device_id());
3507 } else if (p == "midi-control") {
3509 //poke_midi_thread ();
3511 } else if (p == "raid-path") {
3513 setup_raid_path (config.get_raid_path());
3515 } else if (p == "timecode-format") {
3519 } else if (p == "video-pullup") {
3523 } else if (p == "seamless-loop") {
3525 if (play_loop && transport_rolling()) {
3526 // to reset diskstreams etc
3527 request_play_loop (true);
3530 } else if (p == "rf-speed") {
3532 cumulative_rf_motion = 0;
3535 } else if (p == "click-sound") {
3537 setup_click_sounds (1);
3539 } else if (p == "click-emphasis-sound") {
3541 setup_click_sounds (-1);
3543 } else if (p == "clicking") {
3545 if (Config->get_clicking()) {
3546 if (_click_io && click_data) { // don't require emphasis data
3553 } else if (p == "click-gain") {
3556 _click_gain->set_gain (Config->get_click_gain(), this);
3559 } else if (p == "send-mtc") {
3561 if (Config->get_send_mtc ()) {
3562 /* mark us ready to send */
3563 next_quarter_frame_to_send = 0;
3566 } else if (p == "send-mmc") {
3568 _mmc->enable_send (Config->get_send_mmc ());
3570 } else if (p == "midi-feedback") {
3572 session_midi_feedback = Config->get_midi_feedback();
3574 } else if (p == "jack-time-master") {
3576 engine().reset_timebase ();
3578 } else if (p == "native-file-header-format") {
3580 if (!first_file_header_format_reset) {
3581 reset_native_file_format ();
3584 first_file_header_format_reset = false;
3586 } else if (p == "native-file-data-format") {
3588 if (!first_file_data_format_reset) {
3589 reset_native_file_format ();
3592 first_file_data_format_reset = false;
3594 } else if (p == "external-sync") {
3595 if (!config.get_external_sync()) {
3596 drop_sync_source ();
3598 switch_to_sync_source (Config->get_sync_source());
3600 } else if (p == "denormal-model") {
3602 } else if (p == "history-depth") {
3603 set_history_depth (Config->get_history_depth());
3604 } else if (p == "remote-model") {
3605 /* XXX DO SOMETHING HERE TO TELL THE GUI THAT WE NEED
3608 } else if (p == "initial-program-change") {
3610 if (_mmc->output_port() && Config->get_initial_program_change() >= 0) {
3613 buf[0] = MIDI::program; // channel zero by default
3614 buf[1] = (Config->get_initial_program_change() & 0x7f);
3616 _mmc->output_port()->midimsg (buf, sizeof (buf), 0);
3618 } else if (p == "solo-mute-override") {
3619 // catch_up_on_solo_mute_override ();
3620 } else if (p == "listen-position" || p == "pfl-position") {
3621 listen_position_changed ();
3622 } else if (p == "solo-control-is-listen-control") {
3623 solo_control_mode_changed ();
3624 } else if (p == "solo-mute-gain") {
3625 _solo_cut_control->Changed();
3626 } else if (p == "timecode-offset" || p == "timecode-offset-negative") {
3627 last_timecode_valid = false;
3628 } else if (p == "playback-buffer-seconds") {
3629 AudioSource::allocate_working_buffers (frame_rate());
3630 } else if (p == "ltc-source-port") {
3631 reconnect_ltc_input ();
3632 } else if (p == "ltc-sink-port") {
3633 reconnect_ltc_output ();
3634 } else if (p == "timecode-generator-offset") {
3635 ltc_tx_parse_offset();
3642 Session::set_history_depth (uint32_t d)
3644 _history.set_depth (d);
3648 Session::load_diskstreams_2X (XMLNode const & node, int)
3651 XMLNodeConstIterator citer;
3653 clist = node.children();
3655 for (citer = clist.begin(); citer != clist.end(); ++citer) {
3658 /* diskstreams added automatically by DiskstreamCreated handler */
3659 if ((*citer)->name() == "AudioDiskstream" || (*citer)->name() == "DiskStream") {
3660 boost::shared_ptr<AudioDiskstream> dsp (new AudioDiskstream (*this, **citer));
3661 _diskstreams_2X.push_back (dsp);
3663 error << _("Session: unknown diskstream type in XML") << endmsg;
3667 catch (failed_constructor& err) {
3668 error << _("Session: could not load diskstream via XML state") << endmsg;
3676 /** Connect things to the MMC object */
3678 Session::setup_midi_machine_control ()
3680 _mmc = new MIDI::MachineControl;
3681 _mmc->set_ports (_midi_ports->mmc_input_port(), _midi_ports->mmc_output_port());
3683 _mmc->Play.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3684 _mmc->DeferredPlay.connect_same_thread (*this, boost::bind (&Session::mmc_deferred_play, this, _1));
3685 _mmc->Stop.connect_same_thread (*this, boost::bind (&Session::mmc_stop, this, _1));
3686 _mmc->FastForward.connect_same_thread (*this, boost::bind (&Session::mmc_fast_forward, this, _1));
3687 _mmc->Rewind.connect_same_thread (*this, boost::bind (&Session::mmc_rewind, this, _1));
3688 _mmc->Pause.connect_same_thread (*this, boost::bind (&Session::mmc_pause, this, _1));
3689 _mmc->RecordPause.connect_same_thread (*this, boost::bind (&Session::mmc_record_pause, this, _1));
3690 _mmc->RecordStrobe.connect_same_thread (*this, boost::bind (&Session::mmc_record_strobe, this, _1));
3691 _mmc->RecordExit.connect_same_thread (*this, boost::bind (&Session::mmc_record_exit, this, _1));
3692 _mmc->Locate.connect_same_thread (*this, boost::bind (&Session::mmc_locate, this, _1, _2));
3693 _mmc->Step.connect_same_thread (*this, boost::bind (&Session::mmc_step, this, _1, _2));
3694 _mmc->Shuttle.connect_same_thread (*this, boost::bind (&Session::mmc_shuttle, this, _1, _2, _3));
3695 _mmc->TrackRecordStatusChange.connect_same_thread (*this, boost::bind (&Session::mmc_record_enable, this, _1, _2, _3));
3697 /* also handle MIDI SPP because its so common */
3699 _mmc->SPPStart.connect_same_thread (*this, boost::bind (&Session::spp_start, this));
3700 _mmc->SPPContinue.connect_same_thread (*this, boost::bind (&Session::spp_continue, this));
3701 _mmc->SPPStop.connect_same_thread (*this, boost::bind (&Session::spp_stop, this));
3704 boost::shared_ptr<Controllable>
3705 Session::solo_cut_control() const
3707 /* the solo cut control is a bit of an anomaly, at least as of Febrary 2011. There are no other
3708 controls in Ardour that currently get presented to the user in the GUI that require
3709 access as a Controllable and are also NOT owned by some SessionObject (e.g. Route, or MonitorProcessor).
3711 its actually an RCConfiguration parameter, so we use a ProxyControllable to wrap
3712 it up as a Controllable. Changes to the Controllable will just map back to the RCConfiguration
3716 return _solo_cut_control;
3720 Session::rename (const std::string& new_name)
3722 string legal_name = legalize_for_path (new_name);
3728 string const old_sources_root = _session_dir->sources_root();
3730 if (!_writable || (_state_of_the_state & CannotSave)) {
3731 error << _("Cannot rename read-only session.") << endmsg;
3732 return 0; // don't show "messed up" warning
3734 if (record_status() == Recording) {
3735 error << _("Cannot rename session while recording") << endmsg;
3736 return 0; // don't show "messed up" warning
3739 StateProtector stp (this);
3744 * interchange subdirectory
3748 * Backup files are left unchanged and not renamed.
3751 /* Windows requires that we close all files before attempting the
3752 * rename. This works on other platforms, but isn't necessary there.
3753 * Leave it in place for all platforms though, since it may help
3754 * catch issues that could arise if the way Source files work ever
3755 * change (since most developers are not using Windows).
3758 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
3759 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3765 /* pass one: not 100% safe check that the new directory names don't
3769 for (vector<space_and_path>::const_iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3773 /* this is a stupid hack because Glib::path_get_dirname() is
3774 * lexical-only, and so passing it /a/b/c/ gives a different
3775 * result than passing it /a/b/c ...
3778 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3779 oldstr = oldstr.substr (0, oldstr.length() - 1);
3782 string base = Glib::path_get_dirname (oldstr);
3784 newstr = Glib::build_filename (base, legal_name);
3786 cerr << "Looking for " << newstr << endl;
3788 if (Glib::file_test (newstr, Glib::FILE_TEST_EXISTS)) {
3789 cerr << " exists\n";
3798 for (vector<space_and_path>::iterator i = session_dirs.begin(); i != session_dirs.end(); ++i) {
3804 /* this is a stupid hack because Glib::path_get_dirname() is
3805 * lexical-only, and so passing it /a/b/c/ gives a different
3806 * result than passing it /a/b/c ...
3809 if (oldstr[oldstr.length()-1] == G_DIR_SEPARATOR) {
3810 oldstr = oldstr.substr (0, oldstr.length() - 1);
3813 string base = Glib::path_get_dirname (oldstr);
3814 newstr = Glib::build_filename (base, legal_name);
3816 cerr << "for " << oldstr << " new dir = " << newstr << endl;
3818 cerr << "Rename " << oldstr << " => " << newstr << endl;
3819 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3820 cerr << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3821 error << string_compose (_("renaming %s as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3825 /* Reset path in "session dirs" */
3830 /* reset primary SessionDirectory object */
3833 (*_session_dir) = newstr;
3838 /* now rename directory below session_dir/interchange */
3840 string old_interchange_dir;
3841 string new_interchange_dir;
3843 /* use newstr here because we renamed the path
3844 * (folder/directory) that used to be oldstr to newstr above
3847 v.push_back (newstr);
3848 v.push_back (interchange_dir_name);
3849 v.push_back (Glib::path_get_basename (oldstr));
3851 old_interchange_dir = Glib::build_filename (v);
3854 v.push_back (newstr);
3855 v.push_back (interchange_dir_name);
3856 v.push_back (legal_name);
3858 new_interchange_dir = Glib::build_filename (v);
3860 cerr << "Rename " << old_interchange_dir << " => " << new_interchange_dir << endl;
3862 if (::g_rename (old_interchange_dir.c_str(), new_interchange_dir.c_str()) != 0) {
3863 cerr << string_compose (_("renaming %s as %2 failed (%3)"),
3864 old_interchange_dir, new_interchange_dir,
3867 error << string_compose (_("renaming %s as %2 failed (%3)"),
3868 old_interchange_dir, new_interchange_dir,
3877 oldstr = Glib::build_filename (new_path, _current_snapshot_name + statefile_suffix);
3878 newstr= Glib::build_filename (new_path, legal_name + statefile_suffix);
3880 cerr << "Rename " << oldstr << " => " << newstr << endl;
3882 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3883 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3884 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3890 oldstr = Glib::build_filename (new_path, _current_snapshot_name) + history_suffix;
3892 if (Glib::file_test (oldstr, Glib::FILE_TEST_EXISTS)) {
3893 newstr = Glib::build_filename (new_path, legal_name) + history_suffix;
3895 cerr << "Rename " << oldstr << " => " << newstr << endl;
3897 if (::g_rename (oldstr.c_str(), newstr.c_str()) != 0) {
3898 cerr << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endl;
3899 error << string_compose (_("renaming %1 as %2 failed (%3)"), oldstr, newstr, g_strerror (errno)) << endmsg;
3904 /* remove old name from recent sessions */
3905 remove_recent_sessions (_path);
3908 /* update file source paths */
3910 for (SourceMap::iterator i = sources.begin(); i != sources.end(); ++i) {
3911 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
3913 string p = fs->path ();
3914 boost::replace_all (p, old_sources_root, _session_dir->sources_root());
3916 SourceFactory::setup_peakfile(i->second, true);
3920 _current_snapshot_name = new_name;
3925 /* save state again to get everything just right */
3927 save_state (_current_snapshot_name);
3929 /* add to recent sessions */
3931 store_recent_sessions (new_name, _path);
3937 Session::get_session_info_from_path (XMLTree& tree, const string& xmlpath)
3939 if (!Glib::file_test (xmlpath, Glib::FILE_TEST_EXISTS)) {
3943 if (!tree.read (xmlpath)) {
3951 Session::get_info_from_path (const string& xmlpath, float& sample_rate, SampleFormat& data_format)
3954 bool found_sr = false;
3955 bool found_data_format = false;
3957 if (get_session_info_from_path (tree, xmlpath)) {
3963 const XMLProperty* prop;
3964 if ((prop = tree.root()->property (X_("sample-rate"))) != 0) {
3965 sample_rate = atoi (prop->value());
3969 const XMLNodeList& children (tree.root()->children());
3970 for (XMLNodeList::const_iterator c = children.begin(); c != children.end(); ++c) {
3971 const XMLNode* child = *c;
3972 if (child->name() == "Config") {
3973 const XMLNodeList& options (child->children());
3974 for (XMLNodeList::const_iterator oc = options.begin(); oc != options.end(); ++oc) {
3975 const XMLNode* option = *oc;
3976 const XMLProperty* name = option->property("name");
3982 if (name->value() == "native-file-data-format") {
3983 const XMLProperty* value = option->property ("value");
3985 SampleFormat fmt = (SampleFormat) string_2_enum (option->property ("value")->value(), fmt);
3987 found_data_format = true;
3993 if (found_data_format) {
3998 return !(found_sr && found_data_format); // zero if they are both found
4001 typedef std::vector<boost::shared_ptr<FileSource> > SeveralFileSources;
4002 typedef std::map<std::string,SeveralFileSources> SourcePathMap;
4005 Session::bring_all_sources_into_session (boost::function<void(uint32_t,uint32_t,string)> callback)
4009 SourcePathMap source_path_map;
4011 boost::shared_ptr<AudioFileSource> afs;
4016 Glib::Threads::Mutex::Lock lm (source_lock);
4018 cerr << " total sources = " << sources.size();
4020 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4021 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4027 if (fs->within_session()) {
4031 if (source_path_map.find (fs->path()) != source_path_map.end()) {
4032 source_path_map[fs->path()].push_back (fs);
4034 SeveralFileSources v;
4036 source_path_map.insert (make_pair (fs->path(), v));
4042 cerr << " fsources = " << total << endl;
4044 for (SourcePathMap::iterator i = source_path_map.begin(); i != source_path_map.end(); ++i) {
4046 /* tell caller where we are */
4048 string old_path = i->first;
4050 callback (n, total, old_path);
4052 cerr << old_path << endl;
4056 switch (i->second.front()->type()) {
4057 case DataType::AUDIO:
4058 new_path = new_audio_source_path_for_embedded (old_path);
4061 case DataType::MIDI:
4062 /* XXX not implemented yet */
4066 if (new_path.empty()) {
4070 cerr << "Move " << old_path << " => " << new_path << endl;
4072 if (!copy_file (old_path, new_path)) {
4073 cerr << "failed !\n";
4077 /* make sure we stop looking in the external
4078 dir/folder. Remember, this is an all-or-nothing
4079 operations, it doesn't merge just some files.
4081 remove_dir_from_search_path (Glib::path_get_dirname (old_path), i->second.front()->type());
4083 for (SeveralFileSources::iterator f = i->second.begin(); f != i->second.end(); ++f) {
4084 (*f)->set_path (new_path);
4089 save_state ("", false, false);
4095 bool accept_all_files (string const &, void *)
4101 Session::save_as_bring_callback (uint32_t,uint32_t,string)
4103 /* 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.
4108 make_new_media_path (string old_path, string new_session_folder, string new_session_path)
4110 /* typedir is the "midifiles" or "audiofiles" etc. part of the path. */
4112 string typedir = Glib::path_get_basename (Glib::path_get_dirname (old_path));
4114 v.push_back (new_session_folder); /* full path */
4115 v.push_back (interchange_dir_name);
4116 v.push_back (new_session_path); /* just one directory/folder */
4117 v.push_back (typedir);
4118 v.push_back (Glib::path_get_basename (old_path));
4120 return Glib::build_filename (v);
4124 Session::save_as (SaveAs& saveas)
4126 vector<string> files;
4127 string current_folder = Glib::path_get_dirname (_path);
4128 string new_folder = legalize_for_path (saveas.new_name);
4129 string to_dir = Glib::build_filename (saveas.new_parent_folder, new_folder);
4130 int64_t total_bytes = 0;
4134 int32_t internal_file_cnt = 0;
4136 vector<string> do_not_copy_extensions;
4137 do_not_copy_extensions.push_back (statefile_suffix);
4138 do_not_copy_extensions.push_back (pending_suffix);
4139 do_not_copy_extensions.push_back (backup_suffix);
4140 do_not_copy_extensions.push_back (temp_suffix);
4141 do_not_copy_extensions.push_back (history_suffix);
4143 /* get total size */
4145 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4147 /* need to clear this because
4148 * find_files_matching_filter() is cumulative
4153 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4155 all += files.size();
4157 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4159 g_stat ((*i).c_str(), &gsb);
4160 total_bytes += gsb.st_size;
4164 /* save old values so we can switch back if we are not switching to the new session */
4166 string old_path = _path;
4167 string old_name = _name;
4168 string old_snapshot = _current_snapshot_name;
4169 string old_sd = _session_dir->root_path();
4170 vector<string> old_search_path[DataType::num_types];
4171 string old_config_search_path[DataType::num_types];
4173 old_search_path[DataType::AUDIO] = source_search_path (DataType::AUDIO);
4174 old_search_path[DataType::MIDI] = source_search_path (DataType::MIDI);
4175 old_config_search_path[DataType::AUDIO] = config.get_audio_search_path ();
4176 old_config_search_path[DataType::MIDI] = config.get_midi_search_path ();
4178 /* switch session directory */
4180 (*_session_dir) = to_dir;
4182 /* create new tree */
4184 if (!_session_dir->create()) {
4185 saveas.failure_message = string_compose (_("Cannot create new session folder %1"), to_dir);
4190 /* copy all relevant files. Find each location in session_dirs,
4191 * and copy files from there to target.
4194 for (vector<space_and_path>::const_iterator sd = session_dirs.begin(); sd != session_dirs.end(); ++sd) {
4196 /* need to clear this because
4197 * find_files_matching_filter() is cumulative
4202 const size_t prefix_len = (*sd).path.size();
4204 /* Work just on the files within this session dir */
4206 find_files_matching_filter (files, (*sd).path, accept_all_files, 0, false, true, true);
4208 /* add dir separator to protect against collisions with
4209 * track names (e.g. track named "audiofiles" or
4213 static const std::string audiofile_dir_string = string (sound_dir_name) + G_DIR_SEPARATOR;
4214 static const std::string midifile_dir_string = string (midi_dir_name) + G_DIR_SEPARATOR;
4215 static const std::string analysis_dir_string = analysis_dir() + G_DIR_SEPARATOR;
4217 /* copy all the files. Handling is different for media files
4218 than others because of the *silly* subtree we have below the interchange
4219 folder. That really was a bad idea, but I'm not fixing it as part of
4220 implementing ::save_as().
4223 for (vector<string>::iterator i = files.begin(); i != files.end(); ++i) {
4225 std::string from = *i;
4228 string filename = Glib::path_get_basename (from);
4229 std::transform (filename.begin(), filename.end(), filename.begin(), ::toupper);
4230 if (filename == ".DS_STORE") {
4235 if (from.find (audiofile_dir_string) != string::npos) {
4237 /* audio file: only copy if asked */
4239 if (saveas.include_media && saveas.copy_media) {
4241 string to = make_new_media_path (*i, to_dir, new_folder);
4243 info << "media file copying from " << from << " to " << to << endmsg;
4245 if (!copy_file (from, to)) {
4246 throw Glib::FileError (Glib::FileError::IO_ERROR,
4247 string_compose(_("\ncopying \"%1\" failed !"), from));
4251 /* we found media files inside the session folder */
4253 internal_file_cnt++;
4255 } else if (from.find (midifile_dir_string) != string::npos) {
4257 /* midi file: always copy unless
4258 * creating an empty new session
4261 if (saveas.include_media) {
4263 string to = make_new_media_path (*i, to_dir, new_folder);
4265 info << "media file copying from " << from << " to " << to << endmsg;
4267 if (!copy_file (from, to)) {
4268 throw Glib::FileError (Glib::FileError::IO_ERROR, "copy failed");
4272 /* we found media files inside the session folder */
4274 internal_file_cnt++;
4276 } else if (from.find (analysis_dir_string) != string::npos) {
4278 /* make sure analysis dir exists in
4279 * new session folder, but we're not
4280 * copying analysis files here, see
4284 (void) g_mkdir_with_parents (analysis_dir().c_str(), 775);
4289 /* normal non-media file. Don't copy state, history, etc.
4292 bool do_copy = true;
4294 for (vector<string>::iterator v = do_not_copy_extensions.begin(); v != do_not_copy_extensions.end(); ++v) {
4295 if ((from.length() > (*v).length()) && (from.find (*v) == from.length() - (*v).length())) {
4296 /* end of filename matches extension, do not copy file */
4302 if (!saveas.copy_media && from.find (peakfile_suffix) != string::npos) {
4303 /* don't copy peakfiles if
4304 * we're not copying media
4310 string to = Glib::build_filename (to_dir, from.substr (prefix_len));
4312 info << "attempting to make directory/folder " << to << endmsg;
4314 if (g_mkdir_with_parents (Glib::path_get_dirname (to).c_str(), 0755)) {
4315 throw Glib::FileError (Glib::FileError::IO_ERROR, "cannot create required directory");
4318 info << "attempting to copy " << from << " to " << to << endmsg;
4320 if (!copy_file (from, to)) {
4321 throw Glib::FileError (Glib::FileError::IO_ERROR,
4322 string_compose(_("\ncopying \"%1\" failed !"), from));
4327 /* measure file size even if we're not going to copy so that our Progress
4328 signals are correct, since we included these do-not-copy files
4329 in the computation of the total size and file count.
4333 g_stat (from.c_str(), &gsb);
4334 copied += gsb.st_size;
4337 double fraction = (double) copied / total_bytes;
4339 bool keep_going = true;
4341 if (saveas.copy_media) {
4343 /* no need or expectation of this if
4344 * media is not being copied, because
4345 * it will be fast(ish).
4348 /* tell someone "X percent, file M of N"; M is one-based */
4350 boost::optional<bool> res = saveas.Progress (fraction, cnt, all);
4358 throw Glib::FileError (Glib::FileError::FAILED, "copy cancelled");
4364 /* copy optional folders, if any */
4366 string old = plugins_dir ();
4367 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4368 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4369 copy_files (old, newdir);
4372 old = externals_dir ();
4373 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4374 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4375 copy_files (old, newdir);
4378 old = automation_dir ();
4379 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4380 string newdir = Glib::build_filename (to_dir, Glib::path_get_basename (old));
4381 copy_files (old, newdir);
4384 if (saveas.include_media) {
4386 if (saveas.copy_media) {
4387 #ifndef PLATFORM_WINDOWS
4388 /* There are problems with analysis files on
4389 * Windows, because they used a colon in their
4390 * names as late as 4.0. Colons are not legal
4391 * under Windows even if NTFS allows them.
4393 * This is a tricky problem to solve so for
4394 * just don't copy these files. They will be
4395 * regenerated as-needed anyway, subject to the
4396 * existing issue that the filenames will be
4397 * rejected by Windows, which is a separate
4398 * problem (though related).
4401 /* only needed if we are copying media, since the
4402 * analysis data refers to media data
4405 old = analysis_dir ();
4406 if (Glib::file_test (old, Glib::FILE_TEST_EXISTS)) {
4407 string newdir = Glib::build_filename (to_dir, "analysis");
4408 copy_files (old, newdir);
4410 #endif /* PLATFORM_WINDOWS */
4416 _current_snapshot_name = saveas.new_name;
4417 _name = saveas.new_name;
4419 if (saveas.include_media && !saveas.copy_media) {
4421 /* reset search paths of the new session (which we're pretending to be right now) to
4422 include the original session search path, so we can still find all audio.
4425 if (internal_file_cnt) {
4426 for (vector<string>::iterator s = old_search_path[DataType::AUDIO].begin(); s != old_search_path[DataType::AUDIO].end(); ++s) {
4427 ensure_search_path_includes (*s, DataType::AUDIO);
4430 /* we do not do this for MIDI because we copy
4431 all MIDI files if saveas.include_media is
4437 bool was_dirty = dirty ();
4439 save_state ("", false, false, !saveas.include_media);
4440 save_default_options ();
4442 if (saveas.copy_media && saveas.copy_external) {
4443 if (bring_all_sources_into_session (boost::bind (&Session::save_as_bring_callback, this, _1, _2, _3))) {
4444 throw Glib::FileError (Glib::FileError::NO_SPACE_LEFT, "consolidate failed");
4448 saveas.final_session_folder_name = _path;
4450 store_recent_sessions (_name, _path);
4452 if (!saveas.switch_to) {
4454 /* switch back to the way things were */
4458 _current_snapshot_name = old_snapshot;
4460 (*_session_dir) = old_sd;
4466 if (internal_file_cnt) {
4467 /* reset these to their original values */
4468 config.set_audio_search_path (old_config_search_path[DataType::AUDIO]);
4469 config.set_midi_search_path (old_config_search_path[DataType::MIDI]);
4474 /* prune session dirs, and update disk space statistics
4479 session_dirs.clear ();
4480 session_dirs.push_back (sp);
4481 refresh_disk_space ();
4483 /* ensure that all existing tracks reset their current capture source paths
4485 reset_write_sources (true, true);
4487 /* the copying above was based on actually discovering files, not just iterating over the sources list.
4488 But if we're going to switch to the new (copied) session, we need to change the paths in the sources also.
4491 for (SourceMap::const_iterator i = sources.begin(); i != sources.end(); ++i) {
4492 boost::shared_ptr<FileSource> fs = boost::dynamic_pointer_cast<FileSource> (i->second);
4498 if (fs->within_session()) {
4499 string newpath = make_new_media_path (fs->path(), to_dir, new_folder);
4500 fs->set_path (newpath);
4505 } catch (Glib::FileError& e) {
4507 saveas.failure_message = e.what();
4509 /* recursively remove all the directories */
4511 remove_directory (to_dir);
4519 saveas.failure_message = _("unknown reason");
4521 /* recursively remove all the directories */
4523 remove_directory (to_dir);